From ea8320dcf8f94881b2dfaf338a0cc50aadbe2067 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 19 May 2019 22:55:03 +0200 Subject: [PATCH] WIP: LVSDB reader/writer: bugfixes, refactoring, tests. --- src/db/db/dbLayoutToNetlistReader.cc | 21 +- src/db/db/dbLayoutToNetlistReader.h | 13 +- src/db/db/dbLayoutToNetlistWriter.cc | 80 +- src/db/db/dbLayoutVsSchematicWriter.cc | 12 +- src/db/db/dbNetlistCrossReference.cc | 8 +- src/db/db/dbNetlistSpiceReader.cc | 5 + src/db/db/dbNetlistSpiceWriter.cc | 32 +- src/db/db/dbNetlistSpiceWriter.h | 1 + src/db/unit_tests/dbLayoutVsSchematicTests.cc | 38 +- src/db/unit_tests/dbNetlistReaderTests.cc | 31 +- src/db/unit_tests/dbNetlistWriterTests.cc | 159 +++ testdata/algo/l2n_reader_au_4.l2n | 3 - testdata/algo/l2n_writer_au.txt | 3 - testdata/algo/l2n_writer_au_2.txt | 3 - testdata/algo/lvs_test1_au.lvsdb | 991 ++++++++++++++++++ testdata/algo/lvs_test_1.gds | Bin 0 -> 4934 bytes testdata/algo/lvs_test_1.spi | 58 + testdata/algo/nreader1.cir | 2 +- testdata/algo/nreader4.cir | 58 + testdata/algo/nwriter11_au.txt | 34 + testdata/algo/nwriter11b_au.txt | 24 + 21 files changed, 1489 insertions(+), 87 deletions(-) create mode 100644 testdata/algo/lvs_test1_au.lvsdb create mode 100644 testdata/algo/lvs_test_1.gds create mode 100644 testdata/algo/lvs_test_1.spi create mode 100644 testdata/algo/nreader4.cir create mode 100644 testdata/algo/nwriter11_au.txt create mode 100644 testdata/algo/nwriter11b_au.txt diff --git a/src/db/db/dbLayoutToNetlistReader.cc b/src/db/db/dbLayoutToNetlistReader.cc index 48ef7171e..0e5a4ae46 100644 --- a/src/db/db/dbLayoutToNetlistReader.cc +++ b/src/db/db/dbLayoutToNetlistReader.cc @@ -60,7 +60,7 @@ typedef l2n_std_format::keys skeys; typedef l2n_std_format::keys lkeys; LayoutToNetlistStandardReader::LayoutToNetlistStandardReader (tl::InputStream &stream) - : m_stream (stream), m_path (stream.absolute_path ()) + : m_stream (stream), m_path (stream.absolute_path ()), m_dbu (0.0) { skip (); } @@ -147,6 +147,7 @@ static db::Region &layer_by_name (db::LayoutToNetlist *l2n, const std::string &n void LayoutToNetlistStandardReader::read_netlist (db::Netlist *netlist, db::LayoutToNetlist *l2n, bool nested, std::map > *id2net_per_circuit) { + m_dbu = 0.001; int version = 0; std::string description; @@ -182,11 +183,13 @@ void LayoutToNetlistStandardReader::read_netlist (db::Netlist *netlist, db::Layo read_word_or_quoted (description); br.done (); - } else if (l2n && (test (skeys::unit_key) || test (lkeys::unit_key))) { + } else if (test (skeys::unit_key) || test (lkeys::unit_key)) { Brace br (this); - double dbu = read_double (); - l2n->internal_layout ()->dbu (dbu); + m_dbu = read_double (); + if (l2n) { + l2n->internal_layout ()->dbu (m_dbu); + } br.done (); } else if (l2n && (test (skeys::top_key) || test (lkeys::top_key))) { @@ -557,8 +560,7 @@ LayoutToNetlistStandardReader::read_device (db::Netlist *netlist, db::LayoutToNe circuit->add_device (device); db::Coord x = 0, y = 0; - double dbu = l2n->internal_layout ()->dbu (); - db::VCplxTrans dbu_inv (1.0 / dbu); + db::VCplxTrans dbu_inv (1.0 / m_dbu); size_t max_tid = 0; @@ -586,7 +588,7 @@ LayoutToNetlistStandardReader::read_device (db::Netlist *netlist, db::LayoutToNe db::DeviceAbstract *da = device_model_by_name (netlist, n).first; - device->other_abstracts ().push_back (db::DeviceAbstractRef (da, db::DVector (dbu * dx, dbu * dy))); + device->other_abstracts ().push_back (db::DeviceAbstractRef (da, db::DVector (m_dbu * dx, m_dbu * dy))); } else if (test (skeys::connect_key) || test (lkeys::connect_key)) { @@ -659,7 +661,7 @@ LayoutToNetlistStandardReader::read_device (db::Netlist *netlist, db::LayoutToNe } - device->set_position (db::DPoint (dbu * x, dbu * y)); + device->set_position (db::DPoint (m_dbu * x, m_dbu * y)); br.done (); @@ -824,8 +826,7 @@ LayoutToNetlistStandardReader::read_subcircuit (db::Netlist *netlist, db::Layout if (l2n) { - double dbu = l2n->internal_layout ()->dbu (); - subcircuit->set_trans (db::DCplxTrans (mag, angle, mirror, db::DVector (dbu * x, dbu * y))); + subcircuit->set_trans (db::DCplxTrans (mag, angle, mirror, db::DVector (m_dbu * x, m_dbu * y))); db::CellInstArray inst (db::CellInst (circuit_ref->cell_index ()), db::ICplxTrans (mag, angle, mirror, db::Vector (x, y))); db::Cell &ccell = l2n->internal_layout ()->cell (circuit->cell_index ()); diff --git a/src/db/db/dbLayoutToNetlistReader.h b/src/db/db/dbLayoutToNetlistReader.h index 51e000b07..a7dca5dd8 100644 --- a/src/db/db/dbLayoutToNetlistReader.h +++ b/src/db/db/dbLayoutToNetlistReader.h @@ -95,8 +95,16 @@ protected: void read_netlist (Netlist *netlist, db::LayoutToNetlist *l2n, bool nested = false, std::map > *id2net_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); - tl::TextInputStream &stream (); - const std::string &path () const; + + const std::string &path () const + { + return m_path; + } + + tl::TextInputStream &stream () + { + return m_stream; + } struct Connections { @@ -129,6 +137,7 @@ private: tl::TextInputStream m_stream; std::string m_path; std::string m_line; + double m_dbu; tl::Extractor m_ex; db::Point m_ref; }; diff --git a/src/db/db/dbLayoutToNetlistWriter.cc b/src/db/db/dbLayoutToNetlistWriter.cc index 676c6bc21..487c41409 100644 --- a/src/db/db/dbLayoutToNetlistWriter.cc +++ b/src/db/db/dbLayoutToNetlistWriter.cc @@ -90,10 +90,6 @@ void std_writer_impl::write (const db::Netlist *nl, const db::LayoutToNetl *mp_stream << "#%l2n-klayout" << endl; } - if (! Keys::is_short ()) { - *mp_stream << endl << indent << "# General section" << endl << endl; - } - if (version > 0) { *mp_stream << indent << Keys::version_key << "(" << version << ")" << endl; } @@ -116,9 +112,9 @@ void std_writer_impl::write (const db::Netlist *nl, const db::LayoutToNetl *mp_stream << indent << Keys::layer_key << "(" << name_for_layer (l2n, *l); db::LayerProperties lp = ly->get_properties (*l); if (! lp.is_null ()) { - *mp_stream << indent << " " << tl::to_word_or_quoted_string (lp.to_string ()); + *mp_stream << " " << tl::to_word_or_quoted_string (lp.to_string ()); } - *mp_stream << indent << ")" << endl; + *mp_stream << ")" << endl; } if (! Keys::is_short ()) { @@ -131,9 +127,9 @@ void std_writer_impl::write (const db::Netlist *nl, const db::LayoutToNetl if (cb != ce) { *mp_stream << indent << Keys::connect_key << "(" << name_for_layer (l2n, *l); for (db::Connectivity::layer_iterator c = l2n->connectivity ().begin_connected (*l); c != ce; ++c) { - *mp_stream << indent << " " << name_for_layer (l2n, *c); + *mp_stream << " " << name_for_layer (l2n, *c); } - *mp_stream << indent << ")" << endl; + *mp_stream << ")" << endl; } } @@ -146,15 +142,15 @@ void std_writer_impl::write (const db::Netlist *nl, const db::LayoutToNetl if (gb != ge) { if (! any) { if (! Keys::is_short ()) { - *mp_stream << endl << "# Global nets and connectivity" << endl; + *mp_stream << endl << indent << "# Global nets and connectivity" << endl; } any = true; } *mp_stream << indent << Keys::global_key << "(" << name_for_layer (l2n, *l); for (db::Connectivity::global_nets_iterator g = gb; g != ge; ++g) { - *mp_stream << indent << " " << tl::to_word_or_quoted_string (l2n->connectivity ().global_net_name (*g)); + *mp_stream << " " << tl::to_word_or_quoted_string (l2n->connectivity ().global_net_name (*g)); } - *mp_stream << indent << ")" << endl; + *mp_stream << ")" << endl; } } @@ -209,9 +205,13 @@ void std_writer_impl::write (const db::Netlist *netlist, const db::LayoutT net2id->insert (std::make_pair (n.operator-> (), ++id)); } - if (l2n && circuit.begin_nets () != circuit.end_nets ()) { + if (circuit.begin_nets () != circuit.end_nets ()) { if (! Keys::is_short ()) { - *mp_stream << endl << indent << indent1 << "# Nets with their geometries" << endl; + if (l2n) { + *mp_stream << endl << indent << indent1 << "# Nets with their geometries" << endl; + } else { + *mp_stream << endl << indent << indent1 << "# Nets" << endl; + } } for (db::Circuit::const_net_iterator n = circuit.begin_nets (); n != circuit.end_nets (); ++n) { write (netlist, l2n, *n, (*net2id) [n.operator-> ()], indent); @@ -340,42 +340,46 @@ void std_writer_impl::write (const db::Netlist *netlist, const db::LayoutT bool any = false; - reset_geometry_ref (); + if (l2n) { - for (db::Connectivity::layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) { + reset_geometry_ref (); - db::cell_index_type cci = circuit->cell_index (); - db::cell_index_type prev_ci = cci; + for (db::Connectivity::layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) { - for (db::recursive_cluster_shape_iterator si (clusters, *l, cci, net.cluster_id ()); ! si.at_end (); ) { + db::cell_index_type cci = circuit->cell_index (); + db::cell_index_type prev_ci = cci; - // NOTE: we don't recursive into circuits which will later be output. However, as circuits may - // vanish in "purge" but the clusters will still be there we need to recursive into clusters from - // unknown cells. - db::cell_index_type ci = si.cell_index (); - if (ci != prev_ci && ci != cci && (netlist->circuit_by_cell_index (ci) || netlist->device_abstract_by_cell_index (ci))) { + for (db::recursive_cluster_shape_iterator si (clusters, *l, cci, net.cluster_id ()); ! si.at_end (); ) { - si.skip_cell (); + // NOTE: we don't recursive into circuits which will later be output. However, as circuits may + // vanish in "purge" but the clusters will still be there we need to recursive into clusters from + // unknown cells. + db::cell_index_type ci = si.cell_index (); + if (ci != prev_ci && ci != cci && (netlist->circuit_by_cell_index (ci) || netlist->device_abstract_by_cell_index (ci))) { - } else { + si.skip_cell (); - if (! any) { - *mp_stream << indent << indent1 << Keys::net_key << "(" << id; - if (! net.name ().empty ()) { - *mp_stream << " " << Keys::name_key << "(" << tl::to_word_or_quoted_string (net.name ()) << ")"; + } else { + + if (! any) { + *mp_stream << indent << indent1 << Keys::net_key << "(" << id; + if (! net.name ().empty ()) { + *mp_stream << " " << Keys::name_key << "(" << tl::to_word_or_quoted_string (net.name ()) << ")"; + } + *mp_stream << endl; + any = true; } + + *mp_stream << indent << indent2; + write (si.operator-> (), si.trans (), name_for_layer (l2n, *l), true); *mp_stream << endl; - any = true; + + prev_ci = ci; + + ++si; + } - *mp_stream << indent << indent2; - write (si.operator-> (), si.trans (), name_for_layer (l2n, *l), true); - *mp_stream << endl; - - prev_ci = ci; - - ++si; - } } diff --git a/src/db/db/dbLayoutVsSchematicWriter.cc b/src/db/db/dbLayoutVsSchematicWriter.cc index 79379c35b..ec3314c2c 100644 --- a/src/db/db/dbLayoutVsSchematicWriter.cc +++ b/src/db/db/dbLayoutVsSchematicWriter.cc @@ -91,11 +91,7 @@ void std_writer_impl::write (const db::LayoutVsSchematic *lvs) { const int version = 0; - stream () << "#%lvs-klayout" << endl; - - if (! Keys::is_short ()) { - stream () << endl << "# General section" << endl << endl; - } + stream () << "#%lvsdb-klayout" << endl; if (version > 0) { stream () << Keys::version_key << "(" << version << ")" << endl; @@ -127,10 +123,6 @@ void std_writer_impl::write (const db::LayoutVsSchematic *lvs) write (lvs->cross_ref ()); stream () << ")" << endl; } - - if (! Keys::is_short ()) { - stream () << endl; - } } template @@ -191,7 +183,7 @@ void std_writer_impl::write (const db::NetlistCrossReference *xref) tl_assert (pcd != 0); stream () << indent1 << Keys::circuit_key << "(" << name_to_s (c->first) << " " << name_to_s (c->second) << status_to_s (pcd->status) << endl; - stream () << indent2 << Keys::xref_key << endl; + stream () << indent2 << Keys::xref_key << "(" << endl; for (db::NetlistCrossReference::PerCircuitData::net_pairs_const_iterator n = pcd->nets.begin (); n != pcd->nets.end (); ++n) { stream () << indent1 << indent2 << 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) << ")" << endl; diff --git a/src/db/db/dbNetlistCrossReference.cc b/src/db/db/dbNetlistCrossReference.cc index 882a47660..70115c885 100644 --- a/src/db/db/dbNetlistCrossReference.cc +++ b/src/db/db/dbNetlistCrossReference.cc @@ -309,10 +309,10 @@ NetlistCrossReference::gen_end_circuit (const db::Circuit *, const db::Circuit * { mp_per_circuit_data->status = status; - std::sort (mp_per_circuit_data->devices.begin (), mp_per_circuit_data->devices.end (), pair_data_compare > ()); - std::sort (mp_per_circuit_data->pins.begin (), mp_per_circuit_data->pins.end (), pair_data_compare > ()); - std::sort (mp_per_circuit_data->subcircuits.begin (), mp_per_circuit_data->subcircuits.end (), pair_data_compare > ()); - std::sort (mp_per_circuit_data->nets.begin (), mp_per_circuit_data->nets.end (), pair_data_compare > ()); + std::stable_sort (mp_per_circuit_data->devices.begin (), mp_per_circuit_data->devices.end (), pair_data_compare > ()); + std::stable_sort (mp_per_circuit_data->pins.begin (), mp_per_circuit_data->pins.end (), pair_data_compare > ()); + std::stable_sort (mp_per_circuit_data->subcircuits.begin (), mp_per_circuit_data->subcircuits.end (), pair_data_compare > ()); + std::stable_sort (mp_per_circuit_data->nets.begin (), mp_per_circuit_data->nets.end (), pair_data_compare > ()); m_current_circuits = std::pair (0, 0); mp_per_circuit_data = 0; diff --git a/src/db/db/dbNetlistSpiceReader.cc b/src/db/db/dbNetlistSpiceReader.cc index 787ce4f4d..7da814a50 100644 --- a/src/db/db/dbNetlistSpiceReader.cc +++ b/src/db/db/dbNetlistSpiceReader.cc @@ -83,6 +83,11 @@ void NetlistSpiceReader::finish () pop_stream (); } + // purge nets with single connections (this way unconnected pins can be realized) + if (mp_netlist) { + mp_netlist->purge_nets (); + } + mp_stream.reset (0); mp_netlist = 0; mp_circuit = 0; diff --git a/src/db/db/dbNetlistSpiceWriter.cc b/src/db/db/dbNetlistSpiceWriter.cc index fa5736086..fad42af81 100644 --- a/src/db/db/dbNetlistSpiceWriter.cc +++ b/src/db/db/dbNetlistSpiceWriter.cc @@ -32,6 +32,7 @@ namespace db { static const char *allowed_name_chars = "_.:,!+$/&\\#[]"; +static const char *not_connect_prefix = "nc_"; // -------------------------------------------------------------------------------- @@ -196,7 +197,7 @@ std::string NetlistSpiceWriterDelegate::format_params (const db::Device &dev) co // -------------------------------------------------------------------------------- NetlistSpiceWriter::NetlistSpiceWriter (NetlistSpiceWriterDelegate *delegate) - : mp_netlist (0), mp_stream (0), mp_delegate (delegate), m_use_net_names (false) + : mp_netlist (0), mp_stream (0), mp_delegate (delegate), m_use_net_names (false), m_next_net_id (0) { static NetlistSpiceWriterDelegate std_delegate; if (! delegate) { @@ -244,7 +245,7 @@ std::string NetlistSpiceWriter::net_to_string (const db::Net *net) const if (! net) { - return "0"; + return std::string (not_connect_prefix) + tl::to_string (++m_next_net_id); } else { @@ -276,8 +277,7 @@ std::string NetlistSpiceWriter::net_to_string (const db::Net *net) const std::map::const_iterator n = m_net_to_spice_id.find (net); if (! net || n == m_net_to_spice_id.end ()) { - // TODO: this should assert or similar - return "0"; + return tl::to_string (++m_next_net_id); } else { return tl::to_string (n->second); } @@ -364,9 +364,27 @@ void NetlistSpiceWriter::do_write (const std::string &description) // assign internal node numbers to the nets m_net_to_spice_id.clear (); - size_t nid = 0; - for (db::Circuit::const_net_iterator n = circuit.begin_nets (); n != circuit.end_nets (); ++n) { - m_net_to_spice_id.insert (std::make_pair (n.operator-> (), ++nid)); + m_next_net_id = 0; + if (! m_use_net_names) { + + for (db::Circuit::const_net_iterator n = circuit.begin_nets (); n != circuit.end_nets (); ++n) { + m_net_to_spice_id.insert (std::make_pair (n.operator-> (), ++m_next_net_id)); + } + + } else { + + // determine the next net id for non-connected nets such that there is no clash with + // existing names + size_t prefix_len = strlen (not_connect_prefix); + + for (db::Circuit::const_net_iterator n = circuit.begin_nets (); n != circuit.end_nets (); ++n) { + if (n->name ().find (not_connect_prefix) == 0 && n->name ().size () > prefix_len) { + size_t num = 0; + tl::from_string (n->name ().c_str () + prefix_len, num); + m_next_net_id = std::max (m_next_net_id, num); + } + } + } write_circuit_header (circuit); diff --git a/src/db/db/dbNetlistSpiceWriter.h b/src/db/db/dbNetlistSpiceWriter.h index ac3e83e97..13f6c4546 100644 --- a/src/db/db/dbNetlistSpiceWriter.h +++ b/src/db/db/dbNetlistSpiceWriter.h @@ -99,6 +99,7 @@ private: tl::OutputStream *mp_stream; tl::weak_ptr mp_delegate; std::map m_net_to_spice_id; + mutable size_t m_next_net_id; bool m_use_net_names; void do_write (const std::string &description); diff --git a/src/db/unit_tests/dbLayoutVsSchematicTests.cc b/src/db/unit_tests/dbLayoutVsSchematicTests.cc index e941bfffa..49e07711f 100644 --- a/src/db/unit_tests/dbLayoutVsSchematicTests.cc +++ b/src/db/unit_tests/dbLayoutVsSchematicTests.cc @@ -47,6 +47,21 @@ static unsigned int define_layer (db::Layout &ly, db::LayerMap &lmap, int gds_la return lid; } +static void compare_lvsdbs (tl::TestBase *_this, const std::string &path, const std::string &au_path) +{ + tl::InputStream is (path); + tl::InputStream is_au (au_path); + + std::string netlist = is.read_all (); + std::string netlist_au = is_au.read_all (); + + if (netlist != netlist_au) { + _this->raise (tl::sprintf ("Compare failed - see\n actual: %s\n golden: %s", + tl::absolute_file_path (path), + tl::absolute_file_path (au_path))); + } +} + TEST(1_BasicFlow) { db::Layout ly; @@ -222,10 +237,23 @@ TEST(1_BasicFlow) lvs.compare_netlists (&comparer); } - // produce the output - { - // @@@ - lvs.save ("lvs_test_1.lvsdb", false); - } + // save and compare + + std::string path = tmp_file ("tmp_lvstest1.lvsdb"); + lvs.save (path, false); + + std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "lvs_test1_au.lvsdb"); + + compare_lvsdbs (_this, path, au_path); + + // load, save and compare + + db::LayoutVsSchematic lvs2; + + std::string path2 = tmp_file ("tmp_lvstest1b.lvsdb"); + lvs2.load (path); + lvs2.save (path2, false); + + compare_lvsdbs (_this, path2, au_path); } diff --git a/src/db/unit_tests/dbNetlistReaderTests.cc b/src/db/unit_tests/dbNetlistReaderTests.cc index ce21c7797..d633a006d 100644 --- a/src/db/unit_tests/dbNetlistReaderTests.cc +++ b/src/db/unit_tests/dbNetlistReaderTests.cc @@ -39,7 +39,7 @@ TEST(1_BasicReader) reader.read (is, nl); EXPECT_EQ (nl.to_string (), - "circuit TOP ();\n" + "circuit TOP ($1='1',$2='2',$3='4',$4='7');\n" " device RES $1 (A='6',B='1') (R=7650);\n" " device RES $2 (A='3',B='1') (R=7650);\n" " device RES $3 (A='3',B='2') (R=2670);\n" @@ -123,3 +123,32 @@ TEST(3_ReaderWithSubcircuitsAltOrder) "end;\n" ); } + +TEST(4_ReaderWithUnconnectedPins) +{ + db::Netlist nl; + + std::string path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "nreader4.cir"); + + db::NetlistSpiceReader reader; + tl::InputStream is (path); + reader.read (is, nl); + + EXPECT_EQ (nl.to_string (), + "circuit RINGO ($1='1',$2='2',$3='3',$4='4');\n" + " subcircuit INV2PAIR $1 ($1='4',$2='3',$3='4',$4='1',$5='6',$6='2',$7='3');\n" + " subcircuit INV2PAIR $2 ($1='4',$2='3',$3='4',$4=(null),$5='1',$6='5',$7='3');\n" + " subcircuit INV2PAIR $3 ($1='4',$2='3',$3='4',$4=(null),$5='5',$6='8',$7='3');\n" + " subcircuit INV2PAIR $4 ($1='4',$2='3',$3='4',$4=(null),$5='8',$6='7',$7='3');\n" + " subcircuit INV2PAIR $5 ($1='4',$2='3',$3='4',$4=(null),$5='7',$6='6',$7='3');\n" + "end;\n" + "circuit INV2PAIR ($1='1',$2='2',$3='3',$4='4',$5='5',$6='6',$7='7');\n" + " subcircuit INV2 $1 ($1='7',$2='5',$3='4',$4='3',$5='2',$6='1');\n" + " subcircuit INV2 $2 ($1='7',$2='4',$3='6',$4='3',$5='2',$6='1');\n" + "end;\n" + "circuit INV2 ($1='1',$2='2',$3='3',$4='4',$5='5',$6='6');\n" + " device PMOS $1 (S='3',G='2',D='5',B='1') (L=0.25,W=3.5,AS=1.4,AD=1.4,PS=6.85,PD=6.85);\n" + " device NMOS $3 (S='3',G='2',D='4',B='6') (L=0.25,W=3.5,AS=1.4,AD=1.4,PS=6.85,PD=6.85);\n" + "end;\n" + ); +} diff --git a/src/db/unit_tests/dbNetlistWriterTests.cc b/src/db/unit_tests/dbNetlistWriterTests.cc index 0f44f4816..90e9e91dc 100644 --- a/src/db/unit_tests/dbNetlistWriterTests.cc +++ b/src/db/unit_tests/dbNetlistWriterTests.cc @@ -867,6 +867,165 @@ TEST(10_WriterLongLines) compare_netlists (_this, path, au_path); } +TEST(11_WriterNonConnectedPins) +{ + db::Netlist nl; + + db::DeviceClass *rcls = new db::DeviceClassResistor (); + db::DeviceClass *ccls = new db::DeviceClassCapacitor (); + db::DeviceClass *lcls = new db::DeviceClassInductor (); + db::DeviceClass *dcls = new db::DeviceClassDiode (); + db::DeviceClass *m3cls = new db::DeviceClassMOS3Transistor (); + db::DeviceClass *m4cls = new db::DeviceClassMOS4Transistor (); + + rcls->set_name ("RCLS"); + lcls->set_name ("LCLS"); + ccls->set_name ("CCLS"); + dcls->set_name ("DCLS"); + m3cls->set_name ("M3CLS"); + m4cls->set_name ("M4CLS"); + + nl.add_device_class (rcls); + nl.add_device_class (lcls); + nl.add_device_class (ccls); + nl.add_device_class (dcls); + nl.add_device_class (m3cls); + nl.add_device_class (m4cls); + + db::Circuit *circuit1 = new db::Circuit (); + circuit1->set_name ("C1"); + nl.add_circuit (circuit1); + + { + db::Net *n1, *n2, *n3, *n4, *n5; + n1 = new db::Net (); + n1->set_name ("n1"); + circuit1->add_net (n1); + n2 = new db::Net (); + n2->set_name ("n2"); + circuit1->add_net (n2); + n3 = new db::Net (); + n3->set_name ("n3"); + circuit1->add_net (n3); + n4 = new db::Net (); + n4->set_name ("n4"); + circuit1->add_net (n4); + n5 = new db::Net (); + n5->set_name ("n5"); + circuit1->add_net (n5); + + db::Device *ddev1 = new db::Device (m4cls); + ddev1->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_L, 0.25); + ddev1->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_W, 0.18); + ddev1->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_AS, 1.2); + ddev1->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_AD, 0.75); + ddev1->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_PS, 2.2); + ddev1->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_PD, 1.75); + db::Device *ddev2 = new db::Device (m4cls); + ddev2->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_L, 1.4); + ddev2->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_W, 0.25); + ddev2->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_AS, 1.3); + ddev2->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_AD, 0.85); + ddev2->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_PS, 2.3); + ddev2->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_PD, 1.85); + circuit1->add_device (ddev1); + circuit1->add_device (ddev2); + + size_t pid1 = circuit1->add_pin ("p1").id (); + size_t pid2 = circuit1->add_pin ("p2").id (); + size_t pid3 = circuit1->add_pin ("p3").id (); + size_t pid4 = circuit1->add_pin ("p4").id (); + + circuit1->connect_pin (pid1, n1); + circuit1->connect_pin (pid2, n2); + circuit1->connect_pin (pid3, n4); + circuit1->connect_pin (pid4, n5); + + ddev1->connect_terminal (ddev1->device_class ()->terminal_id_for_name ("S"), n1); + ddev1->connect_terminal (ddev1->device_class ()->terminal_id_for_name ("G"), n4); + ddev1->connect_terminal (ddev1->device_class ()->terminal_id_for_name ("D"), n3); + ddev1->connect_terminal (ddev1->device_class ()->terminal_id_for_name ("B"), n5); + ddev2->connect_terminal (ddev2->device_class ()->terminal_id_for_name ("S"), n3); + ddev2->connect_terminal (ddev1->device_class ()->terminal_id_for_name ("G"), n4); + ddev2->connect_terminal (ddev2->device_class ()->terminal_id_for_name ("D"), n2); + ddev2->connect_terminal (ddev1->device_class ()->terminal_id_for_name ("B"), n5); + } + + db::Circuit *circuit2 = new db::Circuit (); + circuit2->set_name ("C2"); + nl.add_circuit (circuit2); + + { + db::Net *n1, *n2, *n3, *n4, *n5; + n1 = new db::Net (); + // this gives a clash with the auto-generated node names with non-connected subcircuit pins + // and terminals - we test proper generation of such names this way + n1->set_name ("nc_10"); + circuit2->add_net (n1); + n2 = new db::Net (); + n2->set_name ("n2"); + circuit2->add_net (n2); + n3 = new db::Net (); + n3->set_name ("n3"); + circuit2->add_net (n3); + n4 = new db::Net (); + n4->set_name ("n4"); + circuit2->add_net (n4); + n5 = new db::Net (); + n5->set_name ("n5"); + circuit2->add_net (n5); + + db::SubCircuit *sc1 = new db::SubCircuit (circuit1, "SC1"); + circuit2->add_subcircuit (sc1); + sc1->connect_pin (0, n1); + sc1->connect_pin (1, n3); + // pin 2 unconnected + sc1->connect_pin (3, n3); + + db::SubCircuit *sc2 = new db::SubCircuit (circuit1, "SC2"); + circuit2->add_subcircuit (sc2); + sc2->connect_pin (0, n3); + // pin 1 unconnected + sc2->connect_pin (2, n4); + sc2->connect_pin (3, n3); + + size_t pid1 = circuit2->add_pin ("p1").id (); + size_t pid2 = circuit2->add_pin ("p2").id (); + size_t pid3 = circuit2->add_pin ("p3").id (); + + circuit2->connect_pin (pid1, n1); + circuit2->connect_pin (pid2, n2); + circuit2->connect_pin (pid3, n4); + } + + // verify against the input + + std::string path = tmp_file ("tmp_nwriter11.txt"); + { + tl::OutputStream stream (path); + db::NetlistSpiceWriter writer; + writer.write (stream, nl, "written by unit test"); + } + + std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "nwriter11_au.txt"); + + compare_netlists (_this, path, au_path); + + path = tmp_file ("tmp_nwriter11b.txt"); + { + tl::OutputStream stream (path); + db::NetlistSpiceWriter writer; + writer.set_use_net_names (true); + writer.write (stream, nl, "written by unit test"); + } + + au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "nwriter11b_au.txt"); + + compare_netlists (_this, path, au_path); +} + + + namespace { class MyDelegate diff --git a/testdata/algo/l2n_reader_au_4.l2n b/testdata/algo/l2n_reader_au_4.l2n index d7e39bdf0..f34df303b 100644 --- a/testdata/algo/l2n_reader_au_4.l2n +++ b/testdata/algo/l2n_reader_au_4.l2n @@ -1,7 +1,4 @@ #%l2n-klayout - -# General section - top(RINGO) unit(0.001) diff --git a/testdata/algo/l2n_writer_au.txt b/testdata/algo/l2n_writer_au.txt index 12e4aa7de..ff5fb9a9a 100644 --- a/testdata/algo/l2n_writer_au.txt +++ b/testdata/algo/l2n_writer_au.txt @@ -1,7 +1,4 @@ #%l2n-klayout - -# General section - top(RINGO) unit(0.001) diff --git a/testdata/algo/l2n_writer_au_2.txt b/testdata/algo/l2n_writer_au_2.txt index 5facbd7bf..f64ee47f8 100644 --- a/testdata/algo/l2n_writer_au_2.txt +++ b/testdata/algo/l2n_writer_au_2.txt @@ -1,7 +1,4 @@ #%l2n-klayout - -# General section - top(RINGO) unit(0.001) diff --git a/testdata/algo/lvs_test1_au.lvsdb b/testdata/algo/lvs_test1_au.lvsdb new file mode 100644 index 000000000..76cf80916 --- /dev/null +++ b/testdata/algo/lvs_test1_au.lvsdb @@ -0,0 +1,991 @@ +#%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($0 1) + pin(IN 2) + pin(OUT 3) + pin(VSS 4) + pin(VDD 5) + pin(BULK 6) + + # Devices and their connections + device($1 D$PMOS + device(D$PMOS$1 800 0) + connect(0 S S) + connect(0 S D) + connect(0 G G) + connect(0 G G) + connect(0 D D) + connect(0 D S) + connect(0 B B) + connect(0 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($3 D$NMOS + device(D$NMOS$1 800 0) + connect(0 S S) + connect(0 S D) + connect(0 G G) + connect(0 G G) + connect(0 D D) + connect(0 D S) + connect(0 B B) + connect(0 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(BULK 1) + pin($1 2) + pin($2 3) + pin($3 4) + pin($4 5) + pin($5 6) + pin($6 7) + + # Subcircuits and their connections + circuit($1 INV2 location(1700 800) + pin($0 7) + pin(IN 5) + pin(OUT 4) + pin(VSS 3) + pin(VDD 2) + pin(BULK 1) + ) + circuit($2 INV2 location(4340 800) + pin($0 7) + pin(IN 4) + pin(OUT 6) + pin(VSS 3) + pin(VDD 2) + pin(BULK 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(FB 1) + pin(OSC 2) + pin(VDD 3) + pin('BULK,VSS' 4) + + # Subcircuits and their connections + circuit($1 INV2PAIR location(19420 -800) + pin(BULK 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(BULK 4) + pin($1 3) + pin($2 4) + pin($4 1) + pin($5 5) + pin($6 3) + ) + circuit($3 INV2PAIR location(3580 -800) + pin(BULK 4) + pin($1 3) + pin($2 4) + pin($4 5) + pin($5 8) + pin($6 3) + ) + circuit($4 INV2PAIR location(8860 -800) + pin(BULK 4) + pin($1 3) + pin($2 4) + pin($4 8) + pin($5 7) + pin($6 3) + ) + circuit($5 INV2PAIR location(14140 -800) + pin(BULK 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($0 1) + pin($1 2) + pin($2 3) + pin($3 4) + pin($4 5) + pin($5 6) + + # Devices and their connections + device($1 PMOS + 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($3 NMOS + 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('5')) + net(6 name('6')) + net(7 name('7')) + + # Outgoing pins and their connections to nets + pin($0 1) + pin($1 2) + pin($2 3) + pin($3 4) + pin($4 5) + pin($5 6) + pin($6 7) + + # Subcircuits and their connections + circuit($1 INV2 + pin($0 7) + pin($1 5) + pin($2 4) + pin($3 3) + pin($4 2) + pin($5 1) + ) + circuit($2 INV2 + pin($0 7) + pin($1 4) + pin($2 6) + 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($0 1) + pin($1 2) + pin($2 3) + pin($3 4) + + # Subcircuits and their connections + circuit($1 INV2PAIR + pin($0 4) + pin($1 3) + pin($2 4) + pin($3 1) + pin($4 5) + pin($5 2) + pin($6 3) + ) + circuit($2 INV2PAIR + pin($0 4) + pin($1 3) + pin($2 4) + pin($4 1) + pin($5 6) + pin($6 3) + ) + circuit($3 INV2PAIR + pin($0 4) + pin($1 3) + pin($2 4) + pin($4 6) + pin($5 7) + pin($6 3) + ) + circuit($4 INV2PAIR + pin($0 4) + pin($1 3) + pin($2 4) + pin($4 7) + pin($5 8) + pin($6 3) + ) + circuit($5 INV2PAIR + pin($0 4) + pin($1 3) + pin($2 4) + pin($4 8) + pin($5 5) + pin($6 3) + ) + + ) +) + +# Cross reference +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(BULK $5 match) + pin(IN $1 match) + pin(OUT $2 match) + pin(VDD $4 match) + pin(VSS $3 match) + device($1 $1 match) + device($3 $3 match) + ) + ) + circuit(INV2PAIR INV2PAIR match + xref( + net(2 2 match) + net(3 3 match) + net(4 4 match) + net(5 5 match) + net(6 6 match) + net(7 7 match) + net(1 1 match) + pin($1 $1 match) + pin($2 $2 match) + pin($3 $3 match) + pin($4 $4 match) + pin($5 $5 match) + pin($6 $6 match) + pin(BULK $0 match) + circuit($1 $1 match) + circuit($2 $2 match) + ) + ) + circuit(RINGO RINGO match + xref( + net(5 6 match) + net(6 5 match) + net(7 8 match) + net(8 7 match) + net(4 4 match) + net(1 1 match) + net(2 2 match) + net(3 3 match) + pin('BULK,VSS' $3 match) + pin(FB $0 match) + pin(OSC $1 match) + pin(VDD $2 match) + circuit($1 $1 match) + circuit($2 $2 match) + circuit($3 $3 match) + circuit($4 $4 match) + circuit($5 $5 match) + ) + ) +) diff --git a/testdata/algo/lvs_test_1.gds b/testdata/algo/lvs_test_1.gds new file mode 100644 index 0000000000000000000000000000000000000000..e5a038cdb69ca4dd14ef4baf5e8d0c6daee06bb2 GIT binary patch literal 4934 zcmb7|U1*kN7{{;o>v`X8ug-m#m`klJ6o-K$!G6&)EG)!u+}GzJK?1Kle9E zAo=_|(w57Y?@CT8vP7C?Rr23b$p<@nwu-bCN}XFif35e%596pLW zgJ7U<%g%n0Vnrlake9p!3-cnAKkoN^W&Vct--x`?_xbZ{Ioglv6^GO} zT6|9aAUXdtW9ah;*3TFg$Tt}KRYr@Gss1N?jQyRc9HfV_>o!{4`E|N}3vvG7d9LD0 zV*!6pN$Vm~!tlvoB&v34*0N;ok4g~q>>OGz#d?wYX4@;lv$;=2s@x&9BT;kF4oKCR zEv+BdOsP_|0I%9s+Il7Oqt-CKXFRRN8Rx5S?a#M=*}JAu?PcpGZQp3|rqR^+r}lsC zNEl9Bq92Bnee@kIK5;4Kr}lq%HVhxbA^&|3-*(v1;*ZZ{`6A6&|KVAY7OX!x>}c`k zc>TxoZ|f&9|G7gt|Am!k;TI9I?nBM`Gz%-{kVqMWTWXD%JnJl1bXGoT$2bk6emh&o znjbY~p{2g|tkrap1BcyKP|my>?@8RqO7#uyBL#7g_v(c-mhSw5Uz z`WUx2={s6ndb9ny%j(yEufEaZb(gdKhK=f1Usc~|@rI3AKIZp4ee8j+={s6{`h2!O zvsQh)DI(u!@tL(*J`T}a+W!SVYyXWFuinb`7w%QRaZr7u#TV{XzdC!@Jd?+ZEIR9X zvtWG%OL1eQYT=ZyT6*@NR%L0hYj6OU8DCCuYjC4_!IGR{W$F#Ftkm`LyU`zJLFK=3 z5slLy>gHwmzx_Y(g%=~gpRc~e%dI}Snrodn`Hx~ngOelN$&MDEIO_MOaj#YGVnu+9 zo%`4>kp0J_7`FybB%{Tf4yyl@H$YY2 z0B>*U>62muKC4;Z1eF%PmUGg^c?mA)+%ChU6jsju9*yr)+Q%EbuV?4BUHC|}Ue(s4 zY|K#73_O>ypRmRb94BXgPtIWKK1!eG7_FbMKF5@v^E~B;81cqUSS?@+-d=*4G+MlI zQ)&hhKF)GDD33_5p{PD-@hrdPfz~7GFUEE;(vQnM-!HNpby$z2x8j1M#k2CSKCM1U zf6XID`f<58|N1-Xlk_{f9qGsAUVn4D`Xv3%QAhf5x!2!zTz!)M_Ir-><8rUR`?mTd z{r(O|`f<6}A8u2hq`z;(k$zn6@wx8scEo#xeK3z^w&Icq#u`i{q=X$C+T-|JJOHK zz5eEQ^-21jqmK0Ba<9MbxcVgh?e`q%$K_ss_ign_`u!b_^y6}`KisB1Nq^snBmKBM z>8IYaliP8Mcj24`%fE^Y9dfjI(3Lv>628d()%2D04_sBBwD=r9^`4yk3iVDQKUhA2 zbNfq2iwCDt`4hg#;EVK?