From f1fc16d55f69287f413d91ba053f5ff025347961 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 22 May 2019 00:46:15 +0200 Subject: [PATCH] WIP: LVS DB model --- src/db/db/dbLayoutToNetlistFormatDefs.cc | 4 + src/db/db/dbLayoutToNetlistFormatDefs.h | 2 + src/db/db/dbLayoutToNetlistWriter.cc | 2 +- src/db/db/dbLayoutVsSchematicFormatDefs.cc | 4 + src/db/db/dbLayoutVsSchematicFormatDefs.h | 3 + src/db/db/dbLayoutVsSchematicWriter.cc | 2 +- .../laybasic/layIndexedNetlistModel.h | 1 + .../laybasic/layNetlistBrowserDialog.cc | 30 +- .../laybasic/layNetlistBrowserModel.cc | 262 +++-- .../laybasic/layNetlistBrowserModel.h | 3 + .../laybasic/layNetlistBrowserPage.cc | 16 +- src/laybasic/laybasic/layNetlistBrowserPage.h | 27 +- .../laybasic/layNetlistCrossReferenceModel.cc | 21 +- .../unit_tests/layNetlistBrowserModelTests.cc | 31 + testdata/lay/lvsdb_browser.lvsdb | 1002 +++++++++++++++++ 15 files changed, 1250 insertions(+), 160 deletions(-) create mode 100644 testdata/lay/lvsdb_browser.lvsdb diff --git a/src/db/db/dbLayoutToNetlistFormatDefs.cc b/src/db/db/dbLayoutToNetlistFormatDefs.cc index 97027d6c6..82f202af8 100644 --- a/src/db/db/dbLayoutToNetlistFormatDefs.cc +++ b/src/db/db/dbLayoutToNetlistFormatDefs.cc @@ -27,6 +27,10 @@ namespace db namespace l2n_std_format { + const char *l2n_magic_string_cstr = "#%l2n-klayout"; + template<> DB_PUBLIC const std::string keys::l2n_magic_string (l2n_magic_string_cstr); + template<> DB_PUBLIC const std::string keys::l2n_magic_string (l2n_magic_string_cstr); + template<> DB_PUBLIC const std::string keys::version_key ("version"); template<> DB_PUBLIC const std::string keys::description_key ("description"); template<> DB_PUBLIC const std::string keys::top_key ("top"); diff --git a/src/db/db/dbLayoutToNetlistFormatDefs.h b/src/db/db/dbLayoutToNetlistFormatDefs.h index 941d888f2..c346ae853 100644 --- a/src/db/db/dbLayoutToNetlistFormatDefs.h +++ b/src/db/db/dbLayoutToNetlistFormatDefs.h @@ -134,6 +134,8 @@ namespace l2n_std_format template struct DB_PUBLIC keys { + static const std::string l2n_magic_string; + static const std::string version_key; static const std::string description_key; static const std::string top_key; diff --git a/src/db/db/dbLayoutToNetlistWriter.cc b/src/db/db/dbLayoutToNetlistWriter.cc index 194b473f5..13737d037 100644 --- a/src/db/db/dbLayoutToNetlistWriter.cc +++ b/src/db/db/dbLayoutToNetlistWriter.cc @@ -87,7 +87,7 @@ void std_writer_impl::write (const db::Netlist *nl, const db::LayoutToNetl const std::string indent (nested ? indent1 : ""); if (! nested) { - *mp_stream << "#%l2n-klayout" << endl; + *mp_stream << Keys::l2n_magic_string << endl; } if (version > 0) { diff --git a/src/db/db/dbLayoutVsSchematicFormatDefs.cc b/src/db/db/dbLayoutVsSchematicFormatDefs.cc index 22557a490..b58a53100 100644 --- a/src/db/db/dbLayoutVsSchematicFormatDefs.cc +++ b/src/db/db/dbLayoutVsSchematicFormatDefs.cc @@ -27,6 +27,10 @@ namespace db namespace lvs_std_format { + const char *lvs_magic_string_cstr = "#%lvsdb-klayout"; + template<> DB_PUBLIC const std::string keys::lvs_magic_string (lvs_magic_string_cstr); + template<> DB_PUBLIC const std::string keys::lvs_magic_string (lvs_magic_string_cstr); + template<> DB_PUBLIC const std::string keys::reference_key ("reference"); template<> DB_PUBLIC const std::string keys::layout_key ("layout"); template<> DB_PUBLIC const std::string keys::xref_key ("xref"); diff --git a/src/db/db/dbLayoutVsSchematicFormatDefs.h b/src/db/db/dbLayoutVsSchematicFormatDefs.h index 3e7d9d3a9..d96c48015 100644 --- a/src/db/db/dbLayoutVsSchematicFormatDefs.h +++ b/src/db/db/dbLayoutVsSchematicFormatDefs.h @@ -49,6 +49,7 @@ namespace db * * Global statements: * + * #%lvsdb-klayout - header line identifies format * version() - file format version [short key: V] * description() - an arbitrary description text [short key: B] * layout([layout]) - layout part [short key: J] @@ -126,6 +127,8 @@ namespace lvs_std_format { typedef l2n_std_format::keys l2n_keys; + static const std::string lvs_magic_string; + static const std::string reference_key; static const std::string layout_key; static const std::string xref_key; diff --git a/src/db/db/dbLayoutVsSchematicWriter.cc b/src/db/db/dbLayoutVsSchematicWriter.cc index 255a98695..edb817a39 100644 --- a/src/db/db/dbLayoutVsSchematicWriter.cc +++ b/src/db/db/dbLayoutVsSchematicWriter.cc @@ -91,7 +91,7 @@ void std_writer_impl::write (const db::LayoutVsSchematic *lvs) { const int version = 0; - stream () << "#%lvsdb-klayout" << endl; + stream () << Keys::lvs_magic_string << endl; if (version > 0) { stream () << Keys::version_key << "(" << version << ")" << endl; diff --git a/src/laybasic/laybasic/layIndexedNetlistModel.h b/src/laybasic/laybasic/layIndexedNetlistModel.h index aa812e271..3bd373435 100644 --- a/src/laybasic/laybasic/layIndexedNetlistModel.h +++ b/src/laybasic/laybasic/layIndexedNetlistModel.h @@ -27,6 +27,7 @@ #include "laybasicCommon.h" #include +#include #include namespace db diff --git a/src/laybasic/laybasic/layNetlistBrowserDialog.cc b/src/laybasic/laybasic/layNetlistBrowserDialog.cc index b94e00b75..228ed8b41 100644 --- a/src/laybasic/laybasic/layNetlistBrowserDialog.cc +++ b/src/laybasic/laybasic/layNetlistBrowserDialog.cc @@ -32,6 +32,8 @@ #include "layConfigurationDialog.h" #include "dbLayoutToNetlist.h" #include "dbRecursiveShapeIterator.h" +#include "dbLayoutToNetlistFormatDefs.h" +#include "dbLayoutVsSchematicFormatDefs.h" #include #include @@ -442,22 +444,38 @@ NetlistBrowserDialog::open_clicked () BEGIN_PROTECTED std::string fmts = tl::to_string (QObject::tr ("All files (*)")); -#if 0 // @@@ would be good to have this: +#if 0 // TODO: would be good to have this: // collect the formats available ... for (tl::Registrar::iterator rdr = tl::Registrar::begin (); rdr != tl::Registrar::end (); ++rdr) { fmts += ";;" + rdr->file_format (); } #else - fmts += ";;L2N DB files (*.l2n)"; - // @@@ TODO: add plain spice + fmts += ";;L2N DB files (*.l2n);;LVS DB files (*.lvsdb)"; + // TODO: add plain spice #endif // prepare and open the file dialog - lay::FileDialog open_dialog (this, tl::to_string (QObject::tr ("Netlist Database File")), fmts); + lay::FileDialog open_dialog (this, tl::to_string (QObject::tr ("Netlist/LVS Database File")), fmts); if (open_dialog.get_open (m_open_filename)) { - std::auto_ptr db (new db::LayoutToNetlist ()); - db->load (m_open_filename); + std::auto_ptr db; + + // TODO: generic concept to detect format + std::string first_line; + { + tl::InputStream stream (m_open_filename); + tl::TextInputStream text_stream (stream); + first_line = text_stream.get_line (); + } + + if (first_line.find (db::lvs_std_format::keys::lvs_magic_string) == 0) { + db::LayoutVsSchematic *lvs_db = new db::LayoutVsSchematic (); + db.reset (lvs_db); + lvs_db->load (m_open_filename); + } else { + db.reset (new db::LayoutToNetlist ()); + db->load (m_open_filename); + } int l2n_index = view ()->add_l2ndb (db.release ()); l2ndb_cb->setCurrentIndex (l2n_index); diff --git a/src/laybasic/laybasic/layNetlistBrowserModel.cc b/src/laybasic/laybasic/layNetlistBrowserModel.cc index 2d543e9a1..16c32f2dd 100644 --- a/src/laybasic/laybasic/layNetlistBrowserModel.cc +++ b/src/laybasic/laybasic/layNetlistBrowserModel.cc @@ -23,6 +23,7 @@ #include "layNetlistBrowserModel.h" #include "layIndexedNetlistModel.h" +#include "layNetlistCrossReferenceModel.h" #include "dbNetlistDeviceClasses.h" #include @@ -205,12 +206,19 @@ static inline bool always (bool) } NetlistBrowserModel::NetlistBrowserModel (QWidget *parent, db::LayoutToNetlist *l2ndb, NetColorizer *colorizer) - : QAbstractItemModel (parent), mp_l2ndb (l2ndb), mp_colorizer (colorizer) + : QAbstractItemModel (parent), mp_l2ndb (l2ndb), mp_lvsdb (0), mp_colorizer (colorizer) { mp_indexer.reset (new SingleIndexedNetlistModel (l2ndb->netlist ())); connect (mp_colorizer, SIGNAL (colors_changed ()), this, SLOT (colors_changed ())); } +NetlistBrowserModel::NetlistBrowserModel (QWidget *parent, db::LayoutVsSchematic *lvsdb, NetColorizer *colorizer) + : QAbstractItemModel (parent), mp_l2ndb (0), mp_lvsdb (lvsdb), mp_colorizer (colorizer) +{ + mp_indexer.reset (new NetlistCrossReferenceModel (lvsdb->cross_ref ())); + connect (mp_colorizer, SIGNAL (colors_changed ()), this, SLOT (colors_changed ())); +} + NetlistBrowserModel::~NetlistBrowserModel () { // .. nothing yet .. @@ -307,6 +315,10 @@ NetlistBrowserModel::make_id_circuit_device_terminal (size_t circuit_index, size bool NetlistBrowserModel::is_id_circuit (void *id) const { + if (mp_indexer->circuit_count () == 0) { + return false; + } + pop (id, mp_indexer->circuit_count ()); return id == 0; } @@ -314,6 +326,10 @@ NetlistBrowserModel::is_id_circuit (void *id) const bool NetlistBrowserModel::is_id_circuit_pin (void *id) const { + if (mp_indexer->circuit_count () == 0) { + return false; + } + IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); pop (id, mp_indexer->circuit_count ()); return (pop (id, 8) == 1 && always (pop (id, mp_indexer->pin_count (circuits))) && id == 0); @@ -322,6 +338,10 @@ NetlistBrowserModel::is_id_circuit_pin (void *id) const bool NetlistBrowserModel::is_id_circuit_pin_net (void *id) const { + if (mp_indexer->circuit_count () == 0) { + return false; + } + IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); pop (id, mp_indexer->circuit_count ()); return (pop (id, 8) == 1 && always (pop (id, mp_indexer->pin_count (circuits))) && id != 0); @@ -330,6 +350,10 @@ NetlistBrowserModel::is_id_circuit_pin_net (void *id) const bool NetlistBrowserModel::is_id_circuit_net (void *id) const { + if (mp_indexer->circuit_count () == 0) { + return false; + } + IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); pop (id, mp_indexer->circuit_count ()); return (pop (id, 8) == 2 && always (pop (id, mp_indexer->net_count (circuits))) && id == 0); @@ -338,24 +362,50 @@ NetlistBrowserModel::is_id_circuit_net (void *id) const bool NetlistBrowserModel::is_id_circuit_net_device_terminal (void *id) const { + if (mp_indexer->circuit_count () == 0) { + return false; + } + + void *org_id = id; + IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - IndexedNetlistModel::net_pair nets = nets_from_id (id); pop (id, mp_indexer->circuit_count ()); - return (pop (id, 8) == 2 && always (pop (id, mp_indexer->net_count (circuits))) && pop (id, 4) == 1 && always (pop (id, mp_indexer->net_terminal_count (nets))) && id == 0); + if (pop (id, 8) == 2 && always (pop (id, mp_indexer->net_count (circuits))) && pop (id, 4) == 1) { + IndexedNetlistModel::net_pair nets = nets_from_id (org_id); + pop (id, mp_indexer->net_terminal_count (nets)); + return id == 0; + } + + return false; } bool NetlistBrowserModel::is_id_circuit_net_device_terminal_others (void *id) const { + if (mp_indexer->circuit_count () == 0) { + return false; + } + + void *org_id = id; + IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - IndexedNetlistModel::net_pair nets = nets_from_id (id); pop (id, mp_indexer->circuit_count ()); - return (pop (id, 8) == 2 && always (pop (id, mp_indexer->net_count (circuits))) && pop (id, 4) == 1 && always (pop (id, mp_indexer->net_terminal_count (nets))) && id != 0); + if (pop (id, 8) == 2 && always (pop (id, mp_indexer->net_count (circuits))) && pop (id, 4) == 1) { + IndexedNetlistModel::net_pair nets = nets_from_id (org_id); + pop (id, mp_indexer->net_terminal_count (nets)); + return id != 0; + } + + return false; } bool NetlistBrowserModel::is_id_circuit_net_pin (void *id) const { + if (mp_indexer->circuit_count () == 0) { + return false; + } + IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); pop (id, mp_indexer->circuit_count ()); return (pop (id, 8) == 2 && always (pop (id, mp_indexer->net_count (circuits))) && pop (id, 4) == 2); @@ -364,24 +414,50 @@ NetlistBrowserModel::is_id_circuit_net_pin (void *id) const bool NetlistBrowserModel::is_id_circuit_net_subcircuit_pin (void *id) const { + if (mp_indexer->circuit_count () == 0) { + return false; + } + + void *org_id = id; + IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - IndexedNetlistModel::net_pair nets = nets_from_id (id); pop (id, mp_indexer->circuit_count ()); - return (pop (id, 8) == 2 && always (pop (id, mp_indexer->net_count (circuits))) && pop (id, 4) == 3 && always (pop (id, mp_indexer->net_subcircuit_pin_count (nets))) && id == 0); + if (pop (id, 8) == 2 && always (pop (id, mp_indexer->net_count (circuits))) && pop (id, 4) == 3) { + IndexedNetlistModel::net_pair nets = nets_from_id (org_id); + pop (id, mp_indexer->net_subcircuit_pin_count (nets)); + return id == 0; + } + + return false; } bool NetlistBrowserModel::is_id_circuit_net_subcircuit_pin_others (void *id) const { + if (mp_indexer->circuit_count () == 0) { + return false; + } + + void *org_id = id; + IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - IndexedNetlistModel::net_pair nets = nets_from_id (id); pop (id, mp_indexer->circuit_count ()); - return (pop (id, 8) == 2 && always (pop (id, mp_indexer->net_count (circuits))) && pop (id, 4) == 3 && always (pop (id, mp_indexer->net_subcircuit_pin_count (nets))) && id != 0); + if (pop (id, 8) == 2 && always (pop (id, mp_indexer->net_count (circuits))) && pop (id, 4) == 3) { + IndexedNetlistModel::net_pair nets = nets_from_id (org_id); + pop (id, mp_indexer->net_subcircuit_pin_count (nets)); + return id != 0; + } + + return false; } bool NetlistBrowserModel::is_id_circuit_subcircuit (void *id) const { + if (mp_indexer->circuit_count () == 0) { + return false; + } + IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); pop (id, mp_indexer->circuit_count ()); return (pop (id, 8) == 3 && always (pop (id, mp_indexer->subcircuit_count (circuits))) && id == 0); @@ -390,6 +466,10 @@ NetlistBrowserModel::is_id_circuit_subcircuit (void *id) const bool NetlistBrowserModel::is_id_circuit_subcircuit_pin (void *id) const { + if (mp_indexer->circuit_count () == 0) { + return false; + } + IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); pop (id, mp_indexer->circuit_count ()); return (pop (id, 8) == 3 && always (pop (id, mp_indexer->subcircuit_count (circuits))) && id != 0); @@ -398,6 +478,10 @@ NetlistBrowserModel::is_id_circuit_subcircuit_pin (void *id) const bool NetlistBrowserModel::is_id_circuit_device (void *id) const { + if (mp_indexer->circuit_count () == 0) { + return false; + } + IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); pop (id, mp_indexer->circuit_count ()); return (pop (id, 8) == 4 && always (pop (id, mp_indexer->device_count (circuits))) && id == 0); @@ -406,6 +490,10 @@ NetlistBrowserModel::is_id_circuit_device (void *id) const bool NetlistBrowserModel::is_id_circuit_device_terminal (void *id) const { + if (mp_indexer->circuit_count () == 0) { + return false; + } + IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); pop (id, mp_indexer->circuit_count ()); return (pop (id, 8) == 4 && always (pop (id, mp_indexer->device_count (circuits))) && id != 0); @@ -884,7 +972,7 @@ NetlistBrowserModel::text (const QModelIndex &index) const if (index.column () == 0) { return tl::to_qstring (str_from_names (circuits, mp_indexer->is_single ())); } else if (!mp_indexer->is_single ()) { - return tl::to_qstring (str_from_name (index.column () == 2 ? circuits.first : circuits.second)); + return tl::to_qstring (str_from_name (index.column () == 1 ? circuits.first : circuits.second)); } } else if (is_id_circuit_pin (id)) { @@ -896,7 +984,7 @@ NetlistBrowserModel::text (const QModelIndex &index) const if (index.column () == 0) { return tl::to_qstring (str_from_expanded_names (pins, mp_indexer->is_single ())); } else if (!mp_indexer->is_single ()) { - return tl::to_qstring (str_from_expanded_name (index.column () == 2 ? pins.first : pins.second)); + return tl::to_qstring (str_from_expanded_name (index.column () == 1 ? pins.first : pins.second)); } } else if (is_id_circuit_pin_net (id)) { @@ -1468,104 +1556,6 @@ NetlistBrowserModel::flags (const QModelIndex & /*index*/) const return Qt::ItemIsEnabled | Qt::ItemIsSelectable; } -static size_t device_rows_for (const db::Circuit *circuit) -{ - if (! circuit) { - return 0; - } else { - return circuit->device_count (); - } -} - -static size_t device_rows_for (const IndexedNetlistModel::circuit_pair &circuits) -{ - return std::max (device_rows_for (circuits.first), device_rows_for (circuits.second)); -} - -static size_t pin_rows_for (const db::Circuit *circuit) -{ - if (! circuit) { - return 0; - } else { - return circuit->pin_count (); - } -} - -static size_t pin_rows_for (const IndexedNetlistModel::circuit_pair &circuits) -{ - return std::max (pin_rows_for (circuits.first), pin_rows_for (circuits.second)); -} - -static size_t net_rows_for (const db::Circuit *circuit) -{ - if (! circuit) { - return 0; - } else { - return circuit->net_count (); - } -} - -static size_t net_rows_for (const IndexedNetlistModel::circuit_pair &circuits) -{ - return std::max (net_rows_for (circuits.first), net_rows_for (circuits.second)); -} - -static size_t subcircuit_rows_for (const db::Circuit *circuit) -{ - if (! circuit) { - return 0; - } else { - return circuit->subcircuit_count (); - } -} - -static size_t subcircuit_rows_for (const IndexedNetlistModel::circuit_pair &circuits) -{ - return std::max (subcircuit_rows_for (circuits.first), subcircuit_rows_for (circuits.second)); -} - -static size_t pin_rows_for (const db::Net *net) -{ - if (! net) { - return 0; - } else { - return net->pin_count (); - } -} - -static size_t pin_rows_for (const IndexedNetlistModel::net_pair &nets) -{ - return std::max (pin_rows_for (nets.first), pin_rows_for (nets.second)); -} - -static size_t subcircuit_rows_for (const db::Net *net) -{ - if (! net) { - return 0; - } else { - return net->subcircuit_pin_count (); - } -} - -static size_t subcircuit_rows_for (const IndexedNetlistModel::net_pair &nets) -{ - return std::max (subcircuit_rows_for (nets.first), subcircuit_rows_for (nets.second)); -} - -static size_t terminal_rows_for (const db::Net *net) -{ - if (! net) { - return 0; - } else { - return net->terminal_count (); - } -} - -static size_t terminal_rows_for (const IndexedNetlistModel::net_pair &nets) -{ - return std::max (terminal_rows_for (nets.first), terminal_rows_for (nets.second)); -} - static size_t rows_for (const db::Device *device) { if (! device || ! device->device_class ()) { @@ -1607,7 +1597,7 @@ NetlistBrowserModel::hasChildren (const QModelIndex &parent) const { if (! parent.isValid ()) { - return mp_l2ndb->netlist () && mp_l2ndb->netlist ()->circuit_count () > 0; + return mp_indexer.get () && mp_indexer->circuit_count () > 0; } else { @@ -1616,10 +1606,10 @@ NetlistBrowserModel::hasChildren (const QModelIndex &parent) const if (is_id_circuit (id)) { IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - return device_rows_for (circuits.first) > 0 || device_rows_for (circuits.second) > 0 || - subcircuit_rows_for (circuits.first) > 0 || subcircuit_rows_for (circuits.second) > 0 || - pin_rows_for (circuits.first) > 0 || pin_rows_for (circuits.second) > 0 || - net_rows_for (circuits.first) > 0 || net_rows_for (circuits.second) > 0; + return mp_indexer->device_count (circuits) > 0 || + mp_indexer->subcircuit_count (circuits) > 0 || + mp_indexer->pin_count (circuits) > 0 || + mp_indexer->net_count (circuits) > 0; } else if (is_id_circuit_pin (id)) { @@ -1638,9 +1628,9 @@ NetlistBrowserModel::hasChildren (const QModelIndex &parent) const } else if (is_id_circuit_net (id)) { IndexedNetlistModel::net_pair nets = nets_from_id (id); - return pin_rows_for (nets.first) > 0 || pin_rows_for (nets.second) > 0 || - terminal_rows_for (nets.first) > 0 || terminal_rows_for (nets.second) > 0 || - subcircuit_rows_for (nets.first) > 0 || subcircuit_rows_for (nets.second) > 0; + return mp_indexer->net_pin_count (nets) > 0 || + mp_indexer->net_terminal_count (nets) > 0 || + mp_indexer->net_subcircuit_pin_count (nets) > 0; } else if (is_id_circuit_net_subcircuit_pin (id)) { @@ -1691,22 +1681,22 @@ NetlistBrowserModel::index (int row, int column, const QModelIndex &parent) cons int r = row; IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - int rpins = int (pin_rows_for (circuits)); + int rpins = int (mp_indexer->pin_count (circuits)); if (r < rpins) { new_id = make_id_circuit_pin (circuit_index_from_id (id), size_t (r)); } else { r -= rpins; - int rnets = int (net_rows_for (circuits)); + int rnets = int (mp_indexer->net_count (circuits)); if (r < int (rnets)) { new_id = make_id_circuit_net (circuit_index_from_id (id), size_t (r)); } else { r -= int (rnets); - int rsubcircuits = int (subcircuit_rows_for (circuits)); + int rsubcircuits = int (mp_indexer->subcircuit_count (circuits)); if (r < rsubcircuits) { new_id = make_id_circuit_subcircuit (circuit_index_from_id (id), size_t (r)); } else { r -= rsubcircuits; - if (r < int (device_rows_for (circuits))) { + if (r < int (mp_indexer->device_count (circuits))) { new_id = make_id_circuit_device (circuit_index_from_id (id), size_t (r)); } } @@ -1729,17 +1719,17 @@ NetlistBrowserModel::index (int row, int column, const QModelIndex &parent) cons int r = row; IndexedNetlistModel::net_pair nets = nets_from_id (id); - int rterminals = int (terminal_rows_for (nets)); + int rterminals = int (mp_indexer->net_terminal_count (nets)); if (r < rterminals){ new_id = make_id_circuit_net_device_terminal (circuit_index_from_id (id), circuit_net_index_from_id (id), size_t (r)); } else { r -= rterminals; - int rpins = int (pin_rows_for (nets)); + int rpins = int (mp_indexer->net_pin_count (nets)); if (r < rpins) { new_id = make_id_circuit_net_pin (circuit_index_from_id (id), circuit_net_index_from_id (id), size_t (r)); } else { r -= rpins; - if (r < int (subcircuit_rows_for (nets))) { + if (r < int (mp_indexer->net_subcircuit_pin_count (nets))) { new_id = make_id_circuit_net_subcircuit_pin (circuit_index_from_id (id), circuit_net_index_from_id (id), size_t (r)); } } @@ -1893,7 +1883,7 @@ NetlistBrowserModel::index_from_id (void *id, int column) const } else if (is_id_circuit_net (id)) { IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - return createIndex (int (pin_rows_for (circuits) + circuit_net_index_from_id (id)), column, id); + return createIndex (int (mp_indexer->pin_count (circuits) + circuit_net_index_from_id (id)), column, id); } else if (is_id_circuit_net_device_terminal (id)) { @@ -1906,12 +1896,12 @@ NetlistBrowserModel::index_from_id (void *id, int column) const } else if (is_id_circuit_net_pin (id)) { IndexedNetlistModel::net_pair nets = nets_from_id (id); - return createIndex (int (terminal_rows_for (nets) + circuit_net_pin_index_from_id (id)), column, id); + return createIndex (int (mp_indexer->net_terminal_count (nets) + circuit_net_pin_index_from_id (id)), column, id); } else if (is_id_circuit_net_subcircuit_pin (id)) { IndexedNetlistModel::net_pair nets = nets_from_id (id); - return createIndex (int (terminal_rows_for (nets) + pin_rows_for (nets) + circuit_net_subcircuit_pin_index_from_id (id)), column, id); + return createIndex (int (mp_indexer->net_terminal_count (nets) + mp_indexer->net_pin_count (nets) + circuit_net_subcircuit_pin_index_from_id (id)), column, id); } else if (is_id_circuit_net_subcircuit_pin_others (id)) { @@ -1920,7 +1910,7 @@ NetlistBrowserModel::index_from_id (void *id, int column) const } else if (is_id_circuit_subcircuit (id)) { IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - return createIndex (int (pin_rows_for (circuits) + net_rows_for (circuits) + circuit_subcircuit_index_from_id (id)), column, id); + return createIndex (int (mp_indexer->pin_count (circuits) + mp_indexer->net_count (circuits) + circuit_subcircuit_index_from_id (id)), column, id); } else if (is_id_circuit_subcircuit_pin (id)) { @@ -1929,7 +1919,7 @@ NetlistBrowserModel::index_from_id (void *id, int column) const } else if (is_id_circuit_device (id)) { IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - return createIndex (int (pin_rows_for (circuits) + net_rows_for (circuits) + subcircuit_rows_for (circuits) + circuit_device_index_from_id (id)), column, id); + return createIndex (int (mp_indexer->pin_count (circuits) + mp_indexer->net_count (circuits) + mp_indexer->subcircuit_count (circuits) + circuit_device_index_from_id (id)), column, id); } else if (is_id_circuit_device_terminal (id)) { @@ -1967,17 +1957,17 @@ NetlistBrowserModel::parent (const QModelIndex &index) const } else if (is_id_circuit_net_device_terminal (id) || is_id_circuit_net_pin (id) || is_id_circuit_net_subcircuit_pin (id)) { IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - return createIndex (int (pin_rows_for (circuits) + circuit_net_index_from_id (id)), column, make_id_circuit_net (circuit_index_from_id (id), circuit_net_index_from_id (id))); + return createIndex (int (mp_indexer->pin_count (circuits) + circuit_net_index_from_id (id)), column, make_id_circuit_net (circuit_index_from_id (id), circuit_net_index_from_id (id))); } else if (is_id_circuit_subcircuit_pin (id)) { IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - return createIndex (int (pin_rows_for (circuits) + net_rows_for (circuits) + circuit_subcircuit_index_from_id (id)), column, make_id_circuit_subcircuit (circuit_index_from_id (id), circuit_subcircuit_index_from_id (id))); + return createIndex (int (mp_indexer->pin_count (circuits) + mp_indexer->net_count (circuits) + circuit_subcircuit_index_from_id (id)), column, make_id_circuit_subcircuit (circuit_index_from_id (id), circuit_subcircuit_index_from_id (id))); } else if (is_id_circuit_device_terminal (id)) { IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - return createIndex (int (pin_rows_for (circuits) + net_rows_for (circuits) + subcircuit_rows_for (circuits) + circuit_device_index_from_id (id)), column, make_id_circuit_device (circuit_index_from_id (id), circuit_device_index_from_id (id))); + return createIndex (int (mp_indexer->pin_count (circuits) + mp_indexer->net_count (circuits) + mp_indexer->subcircuit_count (circuits) + circuit_device_index_from_id (id)), column, make_id_circuit_device (circuit_index_from_id (id), circuit_device_index_from_id (id))); } else if (is_id_circuit_net_device_terminal_others (id)) { @@ -1986,7 +1976,7 @@ NetlistBrowserModel::parent (const QModelIndex &index) const } else if (is_id_circuit_net_subcircuit_pin_others (id)) { IndexedNetlistModel::net_pair nets = nets_from_id (id); - return createIndex (size_t (terminal_rows_for (nets) + pin_rows_for (nets) + circuit_net_subcircuit_pin_index_from_id (id)), column, make_id_circuit_net_subcircuit_pin (circuit_index_from_id (id), circuit_net_index_from_id (id), circuit_net_subcircuit_pin_index_from_id (id))); + return createIndex (size_t (mp_indexer->net_terminal_count (nets) + mp_indexer->net_pin_count (nets) + circuit_net_subcircuit_pin_index_from_id (id)), column, make_id_circuit_net_subcircuit_pin (circuit_index_from_id (id), circuit_net_index_from_id (id), circuit_net_subcircuit_pin_index_from_id (id))); } @@ -2000,7 +1990,7 @@ NetlistBrowserModel::rowCount (const QModelIndex &parent) const { if (! parent.isValid ()) { - return int (mp_l2ndb->netlist ()->circuit_count ()); + return int (mp_indexer.get () ? mp_indexer->circuit_count () : 0); } else { @@ -2009,7 +1999,7 @@ NetlistBrowserModel::rowCount (const QModelIndex &parent) const if (is_id_circuit (id)) { IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - return int (pin_rows_for (circuits) + net_rows_for (circuits) + subcircuit_rows_for (circuits) + device_rows_for (circuits)); + return int (mp_indexer->pin_count (circuits) + mp_indexer->net_count (circuits) + mp_indexer->subcircuit_count (circuits) + mp_indexer->device_count (circuits)); } else if (is_id_circuit_pin (id)) { @@ -2038,7 +2028,7 @@ NetlistBrowserModel::rowCount (const QModelIndex &parent) const } else if (is_id_circuit_net (id)) { IndexedNetlistModel::net_pair nets = nets_from_id (id); - return int (terminal_rows_for (nets) + pin_rows_for (nets) + subcircuit_rows_for (nets)); + return int (mp_indexer->net_terminal_count (nets) + mp_indexer->net_pin_count (nets) + mp_indexer->net_subcircuit_pin_count (nets)); } diff --git a/src/laybasic/laybasic/layNetlistBrowserModel.h b/src/laybasic/laybasic/layNetlistBrowserModel.h index c61d232e2..054a2e8cc 100644 --- a/src/laybasic/laybasic/layNetlistBrowserModel.h +++ b/src/laybasic/laybasic/layNetlistBrowserModel.h @@ -28,6 +28,7 @@ #include "laybasicCommon.h" #include "dbLayoutToNetlist.h" +#include "dbLayoutVsSchematic.h" #include #include @@ -110,6 +111,7 @@ Q_OBJECT public: NetlistBrowserModel (QWidget *parent, db::LayoutToNetlist *l2ndb, NetColorizer *colorizer); + NetlistBrowserModel (QWidget *parent, db::LayoutVsSchematic *lvsdb, NetColorizer *colorizer); ~NetlistBrowserModel (); virtual int columnCount (const QModelIndex &parent) const; @@ -202,6 +204,7 @@ private: QIcon icon_for_connection (const std::pair &net) const; db::LayoutToNetlist *mp_l2ndb; + db::LayoutVsSchematic *mp_lvsdb; NetColorizer *mp_colorizer; std::auto_ptr mp_indexer; mutable std::map m_net_icon_per_color; diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.cc b/src/laybasic/laybasic/layNetlistBrowserPage.cc index a382a836d..3be0c0ff5 100644 --- a/src/laybasic/laybasic/layNetlistBrowserPage.cc +++ b/src/laybasic/laybasic/layNetlistBrowserPage.cc @@ -617,28 +617,34 @@ NetlistBrowserPage::show_all (bool f) } void -NetlistBrowserPage::set_l2ndb (db::LayoutToNetlist *database) +NetlistBrowserPage::set_db (db::LayoutToNetlist *l2ndb) { if (mp_info_dialog) { delete mp_info_dialog; mp_info_dialog = 0; } - mp_database.reset (database); + db::LayoutVsSchematic *lvsdb = dynamic_cast (l2ndb); + mp_database.reset (l2ndb); clear_markers (); highlight (std::vector (), std::vector (), std::vector ()); - if (! database) { + if (! mp_database.get ()) { delete directory_tree->model (); directory_tree->setModel (0); return; } - m_cell_context_cache = db::ContextCache (database->internal_layout ()); + m_cell_context_cache = db::ContextCache (mp_database->internal_layout ()); // NOTE: with the tree as the parent, the tree will take over ownership of the model - NetlistBrowserModel *new_model = new NetlistBrowserModel (directory_tree, database, &m_colorizer); + NetlistBrowserModel *new_model = 0; + if (lvsdb) { + new_model = new NetlistBrowserModel (directory_tree, lvsdb, &m_colorizer); + } else { + new_model = new NetlistBrowserModel (directory_tree, l2ndb, &m_colorizer); + } delete directory_tree->model (); directory_tree->setModel (new_model); diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.h b/src/laybasic/laybasic/layNetlistBrowserPage.h index c549a1855..970049654 100644 --- a/src/laybasic/laybasic/layNetlistBrowserPage.h +++ b/src/laybasic/laybasic/layNetlistBrowserPage.h @@ -29,6 +29,7 @@ #include "layNetlistBrowser.h" #include "laybasicCommon.h" #include "dbLayoutToNetlist.h" +#include "dbLayoutVsSchematic.h" #include "dbLayoutUtils.h" #include "tlObject.h" @@ -82,11 +83,28 @@ public: void set_view (lay::LayoutView *view, unsigned int cv_index); /** - * @brief Attach the page to a L2N DB - * - * To detach the page from any L2N DB, pass 0 for the pointer. + * @brief Attaches the page to a L2N DB */ - void set_l2ndb (db::LayoutToNetlist *database); + void set_l2ndb (db::LayoutToNetlist *database) + { + set_db (database); + } + + /** + * @brief Attaches the page to a LVS DB + */ + void set_lvsdb (db::LayoutVsSchematic *database) + { + set_db (database); + } + + /** + * @brief Detaches the page from any DB + */ + void reset_db () + { + set_db (0); + } /** * @brief Selects a net or clears the selection if net == 0 @@ -188,6 +206,7 @@ private: tl::DeferredMethod dm_update_highlights; db::ContextCache m_cell_context_cache; + void set_db (db::LayoutToNetlist *l2ndb); void add_to_history (void *id, bool fwd); void navigate_to (void *id, bool forward = true); void adjust_view (); diff --git a/src/laybasic/laybasic/layNetlistCrossReferenceModel.cc b/src/laybasic/laybasic/layNetlistCrossReferenceModel.cc index 2a4f01255..00c2aa652 100644 --- a/src/laybasic/laybasic/layNetlistCrossReferenceModel.cc +++ b/src/laybasic/laybasic/layNetlistCrossReferenceModel.cc @@ -39,37 +39,44 @@ size_t NetlistCrossReferenceModel::circuit_count () const size_t NetlistCrossReferenceModel::net_count (const circuit_pair &circuits) const { - return std::max (circuits.first ? circuits.first->net_count () : 0, circuits.second ? circuits.second->net_count () : 0); + const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (circuits); + return data ? data->nets.size () : 0; } size_t NetlistCrossReferenceModel::net_terminal_count (const net_pair &nets) const { - return std::max (nets.first ? nets.first->terminal_count () : 0, nets.second ? nets.second->terminal_count () : 0); + const db::NetlistCrossReference::PerNetData *data = mp_cross_ref->per_net_data_for (nets); + return data ? data->terminals.size () : 0; } size_t NetlistCrossReferenceModel::net_subcircuit_pin_count (const net_pair &nets) const { - return std::max (nets.first ? nets.first->subcircuit_pin_count () : 0, nets.second ? nets.second->subcircuit_pin_count () : 0); + const db::NetlistCrossReference::PerNetData *data = mp_cross_ref->per_net_data_for (nets); + return data ? data->subcircuit_pins.size () : 0; } size_t NetlistCrossReferenceModel::net_pin_count (const net_pair &nets) const { - return std::max (nets.first ? nets.first->pin_count () : 0, nets.second ? nets.second->pin_count () : 0); + const db::NetlistCrossReference::PerNetData *data = mp_cross_ref->per_net_data_for (nets); + return data ? data->pins.size () : 0; } size_t NetlistCrossReferenceModel::device_count (const circuit_pair &circuits) const { - return std::max (circuits.first ? circuits.first->device_count () : 0, circuits.second ? circuits.second->device_count () : 0); + const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (circuits); + return data ? data->devices.size () : 0; } size_t NetlistCrossReferenceModel::pin_count (const circuit_pair &circuits) const { - return std::max (circuits.first ? circuits.first->pin_count () : 0, circuits.second ? circuits.second->pin_count () : 0); + const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (circuits); + return data ? data->pins.size () : 0; } size_t NetlistCrossReferenceModel::subcircuit_count (const circuit_pair &circuits) const { - return std::max (circuits.first ? circuits.first->subcircuit_count () : 0, circuits.second ? circuits.second->subcircuit_count () : 0); + const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (circuits); + return data ? data->subcircuits.size () : 0; } namespace { diff --git a/src/laybasic/unit_tests/layNetlistBrowserModelTests.cc b/src/laybasic/unit_tests/layNetlistBrowserModelTests.cc index b358d3e09..d62813e65 100644 --- a/src/laybasic/unit_tests/layNetlistBrowserModelTests.cc +++ b/src/laybasic/unit_tests/layNetlistBrowserModelTests.cc @@ -217,3 +217,34 @@ TEST (1) EXPECT_EQ (model->rowCount (inv2Device1GateIndex), 0); } +TEST (2) +{ + db::LayoutVsSchematic lvs; + lvs.load (tl::testsrc () + "/testdata/lay/lvsdb_browser.lvsdb"); + + lay::NetColorizer colorizer; + std::auto_ptr model (new lay::NetlistBrowserModel (0, &lvs, &colorizer)); + + EXPECT_EQ (model->hasChildren (QModelIndex ()), true); + // two circuits + EXPECT_EQ (model->rowCount (QModelIndex ()), 4); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, QModelIndex ()), Qt::UserRole).toString ()), "INV2PAIRX"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, QModelIndex ()), Qt::DisplayRole).toString ()), "-/INV2PAIRX"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 1, QModelIndex ()), Qt::DisplayRole).toString ()), ""); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, QModelIndex ()), Qt::DisplayRole).toString ()), "INV2PAIRX"); + EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, QModelIndex ()), Qt::DisplayRole).toString ()), "INV2/INV2"); + EXPECT_EQ (tl::to_string (model->data (model->index (1, 1, QModelIndex ()), Qt::DisplayRole).toString ()), "INV2"); + EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, QModelIndex ()), Qt::DisplayRole).toString ()), "INV2"); + EXPECT_EQ (model->parent (model->index (0, 0, QModelIndex ())).isValid (), false); + EXPECT_EQ (model->parent (model->index (1, 0, QModelIndex ())).isValid (), false); + + EXPECT_EQ (model->hasChildren (model->index (0, 0, QModelIndex ())), false); + EXPECT_EQ (model->rowCount (model->index (0, 0, QModelIndex ())), 0); + + QModelIndex inv2Index = model->index (1, 0, QModelIndex ()); + + EXPECT_EQ (model->hasChildren (inv2Index), true); + EXPECT_EQ (model->rowCount (inv2Index), 14); + + // ... +} diff --git a/testdata/lay/lvsdb_browser.lvsdb b/testdata/lay/lvsdb_browser.lvsdb new file mode 100644 index 000000000..400b27ca9 --- /dev/null +++ b/testdata/lay/lvsdb_browser.lvsdb @@ -0,0 +1,1002 @@ +#%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(bulk '1/0') + layer(nwell '1/0') + layer(poly '3/0') + layer(poly_lbl '3/1') + layer(diff_cont '4/0') + layer(poly_cont '5/0') + layer(metal1 '6/0') + layer(metal1_lbl '6/1') + layer(via1 '7/0') + layer(metal2 '8/0') + layer(metal2_lbl '8/1') + layer(ntie) + layer(psd) + layer(ptie) + layer(nsd) + + # Mask layer connectivity + connect(nwell nwell ntie) + connect(poly poly poly_lbl poly_cont) + connect(poly_lbl poly) + connect(diff_cont diff_cont metal1 ntie psd ptie nsd) + connect(poly_cont poly poly_cont metal1) + connect(metal1 diff_cont poly_cont metal1 metal1_lbl via1) + connect(metal1_lbl metal1) + connect(via1 metal1 via1 metal2) + connect(metal2 via1 metal2 metal2_lbl) + connect(metal2_lbl metal2) + connect(ntie nwell diff_cont ntie) + connect(psd diff_cont psd) + connect(ptie diff_cont ptie) + connect(nsd diff_cont nsd) + + # Global nets and connectivity + global(bulk BULK) + global(ptie BULK) + + # 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(psd (-650 -875) (525 1750)) + ) + terminal(G + rect(poly (-125 -875) (250 1750)) + ) + terminal(D + rect(psd (125 -875) (550 1750)) + ) + terminal(B + rect(nwell (-125 -875) (250 1750)) + ) + ) + device(D$PMOS$1 PMOS + terminal(S + rect(psd (-675 -875) (550 1750)) + ) + terminal(G + rect(poly (-125 -875) (250 1750)) + ) + terminal(D + rect(psd (125 -875) (525 1750)) + ) + terminal(B + rect(nwell (-125 -875) (250 1750)) + ) + ) + device(D$NMOS NMOS + terminal(S + rect(nsd (-650 -875) (525 1750)) + ) + terminal(G + rect(poly (-125 -875) (250 1750)) + ) + terminal(D + rect(nsd (125 -875) (550 1750)) + ) + terminal(B + rect(bulk (-125 -875) (250 1750)) + ) + ) + device(D$NMOS$1 NMOS + terminal(S + rect(nsd (-675 -875) (550 1750)) + ) + terminal(G + rect(poly (-125 -875) (250 1750)) + ) + terminal(D + rect(nsd (125 -875) (525 1750)) + ) + terminal(B + rect(bulk (-125 -875) (250 1750)) + ) + ) + + # Circuit section + # Circuits are the hierarchical building blocks of the netlist. + circuit(INV2 + + # Nets with their geometries + net(1 + rect(nwell (-1400 1800) (2800 3580)) + rect(diff_cont (-1510 -650) (220 220)) + rect(ntie (-510 -450) (800 680)) + ) + net(2 name(IN) + rect(poly (-525 -250) (250 2500)) + rect(poly (-1425 -630) (2100 360)) + rect(poly (-125 -2230) (250 2500)) + rect(poly (-1050 -3850) (250 2400)) + rect(poly (550 1200) (250 2400)) + rect(poly (-250 -6000) (250 2400)) + rect(poly (-1050 1200) (250 2400)) + rect(poly_lbl (-526 -2601) (2 2)) + rect(poly_cont (-831 -111) (220 220)) + ) + net(3 name(OUT) + rect(diff_cont (-910 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(metal1 (1310 -3710) (360 2220)) + rect(metal1 (-1900 -800) (2220 360)) + rect(metal1 (-2280 -2400) (360 2840)) + rect(metal1 (-360 -3600) (360 1560)) + rect(metal1 (1240 2040) (360 1560)) + rect(metal1 (-360 -5160) (360 1560)) + rect(metal1 (-1960 2040) (360 1560)) + rect(metal1_lbl (1419 -2181) (2 2)) + rect(psd (-276 524) (525 1750)) + rect(psd (-2100 -1750) (525 1750)) + rect(nsd (1050 -5350) (525 1750)) + rect(nsd (-2100 -1750) (525 1750)) + ) + net(4 name(VSS) + rect(diff_cont (-110 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 980) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(metal1 (-290 -290) (360 1560)) + rect(metal1 (-360 -1560) (360 1560)) + rect(via1 (-305 -705) (250 250)) + rect(via1 (-250 150) (250 250)) + rect(via1 (-250 -1450) (250 250)) + rect(via1 (-250 150) (250 250)) + rect(metal2 (-1525 -775) (2800 1700)) + rect(metal2_lbl (-161 -541) (2 2)) + rect(nsd (-1516 -1186) (550 1750)) + ) + net(5 name(VDD) + rect(diff_cont (-110 2490) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -1420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(metal1 (-290 -1490) (360 1560)) + rect(metal1 (-360 -1560) (360 1560)) + rect(via1 (-305 -1505) (250 250)) + rect(via1 (-250 150) (250 250)) + rect(via1 (-250 150) (250 250)) + rect(via1 (-250 150) (250 250)) + rect(metal2 (-1525 -1575) (2800 1700)) + rect(metal2_lbl (-151 -1251) (2 2)) + rect(psd (-1526 -476) (550 1750)) + ) + net(6 name(BULK) + rect(diff_cont (-110 -2160) (220 220)) + rect(ptie (-510 -450) (800 680)) + ) + + # Outgoing pins and their connections to nets + pin(1) + pin(2 name(IN)) + pin(3 name(OUT)) + pin(4 name(VSS)) + pin(5 name(VDD)) + pin(6 name(BULK)) + + # Devices and their connections + device(1 D$PMOS + device(D$PMOS$1 800 0) + connect(0 S S) + connect(1 S D) + connect(0 G G) + connect(1 G G) + connect(0 D D) + connect(1 D S) + connect(0 B B) + connect(1 B B) + location(-400 3200) + param(L 0.25) + param(W 3.5) + param(AS 1.4) + param(AD 1.4) + param(PS 6.85) + param(PD 6.85) + terminal(S 3) + terminal(G 2) + terminal(D 5) + terminal(B 1) + ) + device(2 D$NMOS + device(D$NMOS$1 800 0) + connect(0 S S) + connect(1 S D) + connect(0 G G) + connect(1 G G) + connect(0 D D) + connect(1 D S) + connect(0 B B) + connect(1 B B) + location(-400 -400) + param(L 0.25) + param(W 3.5) + param(AS 1.4) + param(AD 1.4) + param(PS 6.85) + param(PD 6.85) + terminal(S 3) + terminal(G 2) + terminal(D 4) + terminal(B 6) + ) + + ) + circuit(INV2PAIR + + # Nets with their geometries + net(1 name(BULK)) + net(2 + rect(diff_cont (4230 3290) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -1420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-2860 -1420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -1420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(metal1 (2350 -1490) (360 1560)) + rect(metal1 (-360 -1560) (360 1560)) + rect(metal1 (-3000 -1560) (360 1560)) + rect(metal1 (-360 -1560) (360 1560)) + ) + net(3 + rect(diff_cont (4230 890) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 980) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-2860 980) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 980) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(metal1 (2350 -290) (360 1560)) + rect(metal1 (-360 -1560) (360 1560)) + rect(metal1 (-3000 -1560) (360 1560)) + rect(metal1 (-360 -1560) (360 1560)) + ) + net(4 + rect(diff_cont (790 890) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(5) + net(6 + rect(diff_cont (3430 890) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(7) + + # Outgoing pins and their connections to nets + pin(1 name(BULK)) + pin(2) + pin(3) + pin(4) + pin(5) + pin(6) + pin(7) + + # Subcircuits and their connections + circuit(1 INV2 location(1700 800) + pin(0 7) + pin(1 5) + pin(2 4) + pin(3 3) + pin(4 2) + pin(5 1) + ) + circuit(2 INV2 location(4340 800) + pin(0 7) + pin(1 4) + pin(2 6) + pin(3 3) + pin(4 2) + pin(5 1) + ) + + ) + circuit(RINGO + + # Nets with their geometries + net(1 name(FB) + rect(diff_cont (20210 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(metal1 (-22130 -2290) (360 360)) + rect(via1 (-305 -305) (250 250)) + rect(via1 (23190 -250) (250 250)) + rect(metal2 (-23765 -325) (23840 400)) + rect(metal2_lbl (-22121 -201) (2 2)) + ) + net(2 name(OSC) + rect(diff_cont (22850 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(via1 (1365 -2235) (250 250)) + rect(metal2 (-325 -325) (400 400)) + rect(metal2_lbl (-201 -201) (2 2)) + ) + net(3 name(VDD) + rect(diff_cont (7810 2490) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -1420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-2860 -1420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -1420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-2860 -1420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -1420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-2860 -1420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -1420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (12980 -1420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -1420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-2860 -1420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -1420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (7700 -1420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -1420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-2860 -1420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -1420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (7700 -1420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -1420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-2860 -1420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -1420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(metal1 (-21410 -10) (360 1120)) + rect(metal1 (2280 -1120) (360 1120)) + rect(metal1 (2280 -1120) (360 1120)) + rect(metal1 (2280 -1120) (360 1120)) + rect(metal1 (2280 -1120) (360 1120)) + rect(metal1 (2280 -1120) (360 1120)) + rect(metal1 (2280 -1120) (360 1120)) + rect(metal1 (2280 -1120) (360 1120)) + rect(metal1 (2280 -1120) (360 1120)) + rect(metal1 (2280 -1120) (360 1120)) + rect(metal1 (-16200 -2600) (360 1560)) + rect(metal1 (-360 -1560) (360 1560)) + rect(metal1 (-3000 -1560) (360 1560)) + rect(metal1 (-360 -1560) (360 1560)) + rect(metal1 (-3000 -1560) (360 1560)) + rect(metal1 (-360 -1560) (360 1560)) + rect(metal1 (-3000 -1560) (360 1560)) + rect(metal1 (-360 -1560) (360 1560)) + rect(metal1 (12840 -1560) (360 1560)) + rect(metal1 (-360 -1560) (360 1560)) + rect(metal1 (-3000 -1560) (360 1560)) + rect(metal1 (-360 -1560) (360 1560)) + rect(metal1 (7560 -1560) (360 1560)) + rect(metal1 (-360 -1560) (360 1560)) + rect(metal1 (-3000 -1560) (360 1560)) + rect(metal1 (-360 -1560) (360 1560)) + rect(metal1 (7560 -1560) (360 1560)) + rect(metal1 (-360 -1560) (360 1560)) + rect(metal1 (-3000 -1560) (360 1560)) + rect(metal1 (-360 -1560) (360 1560)) + rect(metal2_lbl (-21301 -1181) (2 2)) + ) + net(4 name('BULK,VSS') + rect(diff_cont (7810 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 980) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-2860 980) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 980) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-2860 980) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 980) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-2860 980) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 980) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (12980 980) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 980) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-2860 980) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 980) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (7700 980) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 980) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-2860 980) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 980) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (7700 980) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 980) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-2860 980) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 980) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(metal1 (-21410 -1330) (360 1120)) + rect(metal1 (2280 -1120) (360 1120)) + rect(metal1 (2280 -1120) (360 1120)) + rect(metal1 (2280 -1120) (360 1120)) + rect(metal1 (2280 -1120) (360 1120)) + rect(metal1 (2280 -1120) (360 1120)) + rect(metal1 (2280 -1120) (360 1120)) + rect(metal1 (2280 -1120) (360 1120)) + rect(metal1 (2280 -1120) (360 1120)) + rect(metal1 (2280 -1120) (360 1120)) + rect(metal1 (-16200 -80) (360 1560)) + rect(metal1 (-360 -1560) (360 1560)) + rect(metal1 (-3000 -1560) (360 1560)) + rect(metal1 (-360 -1560) (360 1560)) + rect(metal1 (-3000 -1560) (360 1560)) + rect(metal1 (-360 -1560) (360 1560)) + rect(metal1 (-3000 -1560) (360 1560)) + rect(metal1 (-360 -1560) (360 1560)) + rect(metal1 (12840 -1560) (360 1560)) + rect(metal1 (-360 -1560) (360 1560)) + rect(metal1 (-3000 -1560) (360 1560)) + rect(metal1 (-360 -1560) (360 1560)) + rect(metal1 (7560 -1560) (360 1560)) + rect(metal1 (-360 -1560) (360 1560)) + rect(metal1 (-3000 -1560) (360 1560)) + rect(metal1 (-360 -1560) (360 1560)) + rect(metal1 (7560 -1560) (360 1560)) + rect(metal1 (-360 -1560) (360 1560)) + rect(metal1 (-3000 -1560) (360 1560)) + rect(metal1 (-360 -1560) (360 1560)) + rect(metal2_lbl (-21301 -381) (2 2)) + ) + net(5 + rect(diff_cont (1730 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(6 + rect(diff_cont (17570 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(7 + rect(diff_cont (12290 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(8 + rect(diff_cont (7010 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + + # Outgoing pins and their connections to nets + pin(1 name(FB)) + pin(2 name(OSC)) + pin(3 name(VDD)) + pin(4 name('BULK,VSS')) + + # Subcircuits and their connections + circuit(1 INV2PAIR location(19420 -800) + pin(0 4) + pin(1 3) + pin(2 4) + pin(3 1) + pin(4 6) + pin(5 2) + pin(6 3) + ) + circuit(2 INV2PAIR location(-1700 -800) + pin(0 4) + pin(1 3) + pin(2 4) + pin(4 1) + pin(5 5) + pin(6 3) + ) + circuit(3 INV2PAIR location(3580 -800) + pin(0 4) + pin(1 3) + pin(2 4) + pin(4 5) + pin(5 8) + pin(6 3) + ) + circuit(4 INV2PAIR location(8860 -800) + pin(0 4) + pin(1 3) + pin(2 4) + pin(4 8) + pin(5 7) + pin(6 3) + ) + circuit(5 INV2PAIR location(14140 -800) + pin(0 4) + pin(1 3) + pin(2 4) + pin(4 7) + pin(5 6) + pin(6 3) + ) + + ) +) + +# Reference netlist +reference( + + # Device class section + class(PMOS MOS4) + class(NMOS MOS4) + + # Circuit section + # Circuits are the hierarchical building blocks of the netlist. + circuit(INV2 + + # Nets + net(1 name('1')) + net(2 name('2')) + net(3 name('3')) + net(4 name('4')) + net(5 name('5')) + net(6 name('6')) + + # Outgoing pins and their connections to nets + pin(1) + pin(2) + pin(3) + pin(4) + pin(5) + pin(6) + + # Devices and their connections + device(1 PMOS + name($1) param(L 0.25) + param(W 3.5) + param(AS 1.4) + param(AD 1.4) + param(PS 6.85) + param(PD 6.85) + terminal(S 3) + terminal(G 2) + terminal(D 5) + terminal(B 1) + ) + device(2 NMOS + name($3) param(L 0.25) + param(W 3.5) + param(AS 1.4) + param(AD 1.4) + param(PS 6.85) + param(PD 6.85) + terminal(S 3) + terminal(G 2) + terminal(D 4) + terminal(B 6) + ) + + ) + circuit(INV2PAIR + + # Nets + net(1 name('1')) + net(2 name('2')) + net(3 name('3')) + net(4 name('4')) + net(5 name('6')) + net(6 name('7')) + + # Outgoing pins and their connections to nets + pin(1) + pin(2) + pin(3) + pin(4) + pin() + pin(5) + pin(6) + + # Subcircuits and their connections + circuit(1 INV2 name($2) + pin(0 6) + pin(1 4) + pin(2 5) + pin(3 3) + pin(4 2) + pin(5 1) + ) + + ) + circuit(RINGO + + # Nets + net(1 name('1')) + net(2 name('2')) + net(3 name('3')) + net(4 name('4')) + net(5 name('6')) + net(6 name('5')) + net(7 name('8')) + net(8 name('7')) + + # Outgoing pins and their connections to nets + pin(1) + pin(2) + pin(3) + pin(4) + + # Subcircuits and their connections + circuit(1 INV2PAIR name($1) + pin(0 4) + pin(1 3) + pin(2 4) + pin(3 1) + pin(4 5) + pin(5 2) + pin(6 3) + ) + circuit(2 INV2PAIR name($2) + pin(0 4) + pin(1 3) + pin(2 4) + pin(3 1) + pin(4 1) + pin(5 6) + pin(6 3) + ) + circuit(3 INV2PAIR name($3) + pin(0 4) + pin(1 3) + pin(2 4) + pin(4 6) + pin(5 7) + pin(6 3) + ) + circuit(4 INV2PAIR name($4) + pin(0 4) + pin(1 3) + pin(2 4) + pin(4 7) + pin(5 8) + pin(6 3) + ) + circuit(5 INV2PAIR name($5) + pin(0 4) + pin(1 3) + pin(2 4) + pin(4 8) + pin(5 5) + pin(6 3) + ) + + ) + circuit(INV2PAIRX + + # Nets + net(1 name('1')) + net(2 name('2')) + net(3 name('3')) + net(4 name('4')) + net(5 name('6')) + net(6 name('7')) + + # Outgoing pins and their connections to nets + pin(1) + pin(2) + pin(3) + pin(4) + pin() + pin(5) + pin(6) + + # Subcircuits and their connections + circuit(1 INV2 name($2) + pin(0 6) + pin(1 4) + pin(2 5) + pin(3 3) + pin(4 2) + pin(5 1) + ) + + ) +) + +# Cross reference +xref( + circuit(() INV2PAIRX mismatch + xref( + ) + ) + circuit(INV2 INV2 match + xref( + net(1 1 match) + net(6 6 match) + net(2 2 match) + net(3 3 match) + net(5 5 match) + net(4 4 match) + pin(0 0 match) + pin(5 5 match) + pin(1 1 match) + pin(2 2 match) + pin(4 4 match) + pin(3 3 match) + device(1 1 match) + device(2 2 match) + ) + ) + circuit(INV2PAIR INV2PAIR nomatch + xref( + net(4 () mismatch) + net(2 2 mismatch) + net(3 3 mismatch) + net(5 4 match) + net(6 5 match) + net(7 6 mismatch) + net(1 1 mismatch) + pin(() 4 mismatch) + pin(3 () mismatch) + pin(1 1 match) + pin(2 2 match) + pin(4 3 match) + pin(5 5 match) + pin(6 6 match) + pin(0 0 match) + circuit(() 1 mismatch) + circuit(1 () mismatch) + circuit(2 () mismatch) + ) + ) + circuit(RINGO RINGO skipped + xref( + ) + ) +)