From 8213e71a792f4c1c376bf78a8ab41b6e6de8f126 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 19 Jan 2019 22:19:08 +0100 Subject: [PATCH] WIP: l2n reader implementation, some bug fixes, refactoring. --- src/db/db/db.pro | 6 +- src/db/db/dbHierNetworkProcessor.cc | 5 - src/db/db/dbLayoutToNetlist.cc | 33 +- src/db/db/dbLayoutToNetlist.h | 28 + src/db/db/dbLayoutToNetlistFormatDefs.cc | 73 ++ src/db/db/dbLayoutToNetlistFormatDefs.h | 118 +++ src/db/db/dbLayoutToNetlistReader.cc | 688 ++++++++++++++++++ src/db/db/dbLayoutToNetlistReader.h | 75 +- src/db/db/dbLayoutToNetlistWriter.cc | 222 +++--- src/db/db/dbLayoutToNetlistWriter.h | 16 +- src/db/db/dbNetlistDeviceExtractor.cc | 10 +- src/db/db/dbNetlistExtractor.cc | 34 +- src/db/db/gsiDeclDbLayoutToNetlist.cc | 6 +- .../dbLayoutToNetlistReaderTests.cc | 66 ++ .../dbLayoutToNetlistWriterTests.cc | 2 +- src/db/unit_tests/unit_tests.pro | 3 +- testdata/algo/l2n_writer_au.txt | 298 ++++---- 17 files changed, 1364 insertions(+), 319 deletions(-) create mode 100644 src/db/db/dbLayoutToNetlistFormatDefs.cc create mode 100644 src/db/db/dbLayoutToNetlistFormatDefs.h create mode 100644 src/db/unit_tests/dbLayoutToNetlistReaderTests.cc diff --git a/src/db/db/db.pro b/src/db/db/db.pro index 8401e0aef..8ad80e277 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -161,7 +161,8 @@ SOURCES = \ dbPin.cc \ dbLayoutToNetlistReader.cc \ dbLayoutToNetlistWriter.cc \ - dbDeviceModel.cc + dbDeviceModel.cc \ + dbLayoutToNetlistFormatDefs.cc HEADERS = \ dbArray.h \ @@ -287,7 +288,8 @@ HEADERS = \ dbSubCircuit.h \ dbLayoutToNetlistReader.h \ dbLayoutToNetlistWriter.h \ - dbDeviceModel.h + dbDeviceModel.h \ + dbLayoutToNetlistFormatDefs.h !equals(HAVE_QT, "0") { diff --git a/src/db/db/dbHierNetworkProcessor.cc b/src/db/db/dbHierNetworkProcessor.cc index fb2ea01f1..8ad42cd7d 100644 --- a/src/db/db/dbHierNetworkProcessor.cc +++ b/src/db/db/dbHierNetworkProcessor.cc @@ -1664,11 +1664,6 @@ template void hier_clusters::build_local_cluster (const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn) { - if (m_per_cell_clusters.find (cell.cell_index ()) != m_per_cell_clusters.end ()) { - // skip pre-build clusters (from devices) - return; - } - std::string msg = tl::to_string (tr ("Computing local clusters for cell: ")) + std::string (layout.cell_name (cell.cell_index ())); if (tl::verbosity () >= 40) { tl::log << msg; diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index 8d8a89381..81127318e 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -78,6 +78,18 @@ size_t LayoutToNetlist::max_vertex_count () const return m_dss.max_vertex_count (); } +db::Region *LayoutToNetlist::make_layer (const std::string &n) +{ + db::RecursiveShapeIterator si (m_iter); + si.shape_flags (db::ShapeIterator::Nothing); + + db::Region *region = new db::Region (si, m_dss); + if (! n.empty ()) { + name (*region, n); + } + return region; +} + db::Region *LayoutToNetlist::make_layer (unsigned int layer_index, const std::string &n) { db::RecursiveShapeIterator si (m_iter); @@ -199,8 +211,6 @@ void LayoutToNetlist::extract_netlist () mp_netlist.reset (new db::Netlist ()); } - m_net_clusters.clear (); - db::NetlistExtractor netex; netex.extract_nets(m_dss, m_conn, *mp_netlist, m_net_clusters); @@ -217,6 +227,16 @@ const db::Cell *LayoutToNetlist::internal_top_cell () const return &m_dss.const_initial_cell (); } +db::Layout *LayoutToNetlist::internal_layout () +{ + return &m_dss.layout (); +} + +db::Cell *LayoutToNetlist::internal_top_cell () +{ + return &m_dss.initial_cell (); +} + void LayoutToNetlist::name (const db::Region ®ion, const std::string &name) { unsigned int li = layer_of (region); @@ -269,6 +289,15 @@ db::Netlist *LayoutToNetlist::netlist () const return mp_netlist.get (); } +db::Netlist *LayoutToNetlist::make_netlist () +{ + if (! mp_netlist.get ()) { + mp_netlist.reset (new db::Netlist ()); + } + return mp_netlist.get (); +} + + template static void deliver_shape (const db::PolygonRef &pr, db::Region ®ion, const Tr &tr) { diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h index df01397c1..7a0be2655 100644 --- a/src/db/db/dbLayoutToNetlist.h +++ b/src/db/db/dbLayoutToNetlist.h @@ -133,6 +133,11 @@ public: return internal_layout ()->get_properties (layer_of (region)).name; } + /** + * @brief Creates a new empty region + */ + db::Region *make_layer (const std::string &n); + /** * @brief Creates a new region representing an original layer * "layer_index" is the layer index of the desired layer in the original layout. @@ -216,6 +221,16 @@ public: */ const db::Cell *internal_top_cell () const; + /** + * @brief Gets the internal layout (non-const version) + */ + db::Layout *internal_layout (); + + /** + * @brief Gets the internal top cell (non-const version) + */ + db::Cell *internal_top_cell (); + /** * @brief Gets the connectivity object */ @@ -251,6 +266,11 @@ public: */ db::Netlist *netlist () const; + /** + * @brief gets the netlist extracted or make on if none exists yet. + */ + db::Netlist *make_netlist (); + /** * @brief Gets the hierarchical shape clusters derived in the net extraction. * NOTE: the layer and cell indexes used inside this structure refer to the @@ -261,6 +281,14 @@ public: return m_net_clusters; } + /** + * @brief Gets the hierarchical shape clusters derived in the net extraction (non-conver version) + */ + db::hier_clusters &net_clusters () + { + return m_net_clusters; + } + /** * @brief Returns all shapes of a specific net and layer. * diff --git a/src/db/db/dbLayoutToNetlistFormatDefs.cc b/src/db/db/dbLayoutToNetlistFormatDefs.cc new file mode 100644 index 000000000..572fdccb8 --- /dev/null +++ b/src/db/db/dbLayoutToNetlistFormatDefs.cc @@ -0,0 +1,73 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2019 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include "dbLayoutToNetlistFormatDefs.h" + +namespace db +{ + +namespace l2n_std_format +{ + 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"); + template<> DB_PUBLIC const std::string keys::unit_key ("unit"); + template<> DB_PUBLIC const std::string keys::layer_key ("layer"); + template<> DB_PUBLIC const std::string keys::connect_key ("connect"); + template<> DB_PUBLIC const std::string keys::global_key ("global"); + template<> DB_PUBLIC const std::string keys::circuit_key ("circuit"); + template<> DB_PUBLIC const std::string keys::net_key ("net"); + template<> DB_PUBLIC const std::string keys::device_key ("device"); + template<> DB_PUBLIC const std::string keys::polygon_key ("polygon"); + template<> DB_PUBLIC const std::string keys::rect_key ("rect"); + template<> DB_PUBLIC const std::string keys::terminal_key ("terminal"); + template<> DB_PUBLIC const std::string keys::abstract_key ("abstract"); + template<> DB_PUBLIC const std::string keys::param_key ("param"); + template<> DB_PUBLIC const std::string keys::location_key ("location"); + template<> DB_PUBLIC const std::string keys::rotation_key ("rotation"); + template<> DB_PUBLIC const std::string keys::mirror_key ("mirror"); + template<> DB_PUBLIC const std::string keys::scale_key ("scale"); + template<> DB_PUBLIC const std::string keys::pin_key ("pin"); + + template<> DB_PUBLIC const std::string keys::version_key ("V"); + template<> DB_PUBLIC const std::string keys::description_key ("B"); + template<> DB_PUBLIC const std::string keys::top_key ("W"); + template<> DB_PUBLIC const std::string keys::unit_key ("U"); + template<> DB_PUBLIC const std::string keys::layer_key ("L"); + template<> DB_PUBLIC const std::string keys::connect_key ("C"); + template<> DB_PUBLIC const std::string keys::global_key ("G"); + template<> DB_PUBLIC const std::string keys::circuit_key ("X"); + template<> DB_PUBLIC const std::string keys::net_key ("N"); + template<> DB_PUBLIC const std::string keys::device_key ("D"); + template<> DB_PUBLIC const std::string keys::polygon_key ("Q"); + template<> DB_PUBLIC const std::string keys::rect_key ("R"); + template<> DB_PUBLIC const std::string keys::terminal_key ("T"); + template<> DB_PUBLIC const std::string keys::abstract_key ("A"); + template<> DB_PUBLIC const std::string keys::param_key ("E"); + template<> DB_PUBLIC const std::string keys::location_key ("Y"); + template<> DB_PUBLIC const std::string keys::rotation_key ("O"); + template<> DB_PUBLIC const std::string keys::mirror_key ("M"); + template<> DB_PUBLIC const std::string keys::scale_key ("S"); + template<> DB_PUBLIC const std::string keys::pin_key ("P"); +} + +} diff --git a/src/db/db/dbLayoutToNetlistFormatDefs.h b/src/db/db/dbLayoutToNetlistFormatDefs.h new file mode 100644 index 000000000..8d0a6e894 --- /dev/null +++ b/src/db/db/dbLayoutToNetlistFormatDefs.h @@ -0,0 +1,118 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2019 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#ifndef HDR_dbLayoutToNetlistFormatDefs +#define HDR_dbLayoutToNetlistFormatDefs + +#include "dbCommon.h" + +#include + +namespace db +{ + +/** + * This is the internal persistency format for LayoutToNetlist + * + * It's intentionally *not* XML to keep the overhead low. + * + * Comments are introduced by hash: # ... + * Names are words (alphanumerical plus "$", "_", ".") or enclosed in single or double quotes. + * Escape character is backslash. + * Separator is either , or whitespace. Keywords and names are case sensitive. + * Short keys are provided for compacter representation. Short keys can be + * non-alpha (e.g. "*") or empty. + * Single-valued attributes can be given without brackets. + * All dimensions are in units of database unit. + * The file follows the declaration-before-use principle + * (circuits before subcircuits, nets before use ...) + * + * Global statements: + * + * version() - file format version [short key: V] + * description() - an arbitrary description text [short key: B] + * unit() - specifies the database unit [short key: U] + * top() - specifies the name of the top circuit [short key: W] + * layer() - define a layer [short key: L] + * connect( ...) - connects layer1 with the following layers [short key: C] + * global( ...) - connects a layer with the given global nets [short key: G] + * circuit( [circuit-def]) - circuit (cell) [short key: X] + * device( [device-abstract-def]) + * - device abstract [short key: D] + * + * [circuit-def]: + * + * net( [geometry-def]) - net geometry [short key: N] + * A net declaration shall be there also if no geometry + * is present + * pin( ) - outgoing pin connection [short key: P] + * device( [device-def]) + * - device with connections [short key: D] + * circuit( [circuit-def]) - subcircuit with connections [short key: X] + * + * [geometry-def]: + * + * polygon( ...) - defines a polygon [short key: Q] + * rect( ) + * - defines a rectangle [short key: R] + * + * [device-abstract-def]: + * + * terminal( [geometry-def]) + * - specifies the terminal geometry [short key: T] + * + * [device-def]: + * + * location( ) - location of the device [short key Y] + * must be before terminal + * param( ) - defines a parameter [short key E] + * terminal( ) + * - specifies connection of the terminal with + * a net (short key: T) + * + * [subcircuit-def]: + * + * location( ) - location of the subcircuit [short key Y] + * rotation() - rotation angle (in degree, default is 0) [short key O] + * mirror - if specified, the instance is mirrored before rotation [short key M] + * scale() - magnification (default is 1) [short key S] + * pin( ) - specifies connection of the pin with a net [short key: P] + */ + +namespace l2n_std_format +{ + template + struct DB_PUBLIC keys + { + static const std::string version_key, description_key, top_key, unit_key, + layer_key, connect_key, global_key, + circuit_key, net_key, device_key, subcircuit_key, + polygon_key, rect_key, terminal_key, abstract_key, + param_key, location_key, rotation_key, + mirror_key, scale_key, pin_key, + indent1, indent2; + }; +} + +} + +#endif diff --git a/src/db/db/dbLayoutToNetlistReader.cc b/src/db/db/dbLayoutToNetlistReader.cc index 192a6057d..fe3a3ac5b 100644 --- a/src/db/db/dbLayoutToNetlistReader.cc +++ b/src/db/db/dbLayoutToNetlistReader.cc @@ -21,10 +21,698 @@ */ #include "dbLayoutToNetlistReader.h" +#include "dbLayoutToNetlistFormatDefs.h" +#include "dbLayoutToNetlist.h" namespace db { +namespace l2n_std_reader { +class Layers +{ +public: + Layers () { } + + ~Layers () + { + for (std::map::const_iterator i = m_layers.begin (); i != m_layers.end (); ++i) { + delete i->second; + } + m_layers.clear (); + } + + void add (const std::string &name, db::Region *region) + { + if (m_layers.find (name) != m_layers.end ()) { + delete region; + throw tl::Exception (tl::to_string (tr ("Duplicate layer name: ")) + name); + } + m_layers.insert (std::make_pair (name, region)); + } + + db::Region &layer (const std::string &name) + { + std::map::const_iterator l = m_layers.find (name); + if (l == m_layers.end ()) { + throw tl::Exception (tl::to_string (tr ("Not a valid layer name: ")) + name); + } + return *l->second; + } + +private: + std::map m_layers; +}; + +class Brace +{ +public: + Brace (LayoutToNetlistStandardReader *reader) : mp_reader (reader), m_checked (false) + { + m_has_brace = reader->test ("("); + } + + operator bool () + { + if (! m_has_brace) { + m_checked = true; + return false; + } else if (mp_reader->test (")")) { + m_checked = true; + return false; + } else { + return true; + } + } + + void done () + { + if (m_has_brace && ! m_checked) { + mp_reader->expect (")"); + m_checked = true; + } + } + +private: + LayoutToNetlistStandardReader *mp_reader; + bool m_checked; + bool m_has_brace; +}; + +} + +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 ()) +{ + skip (); +} + +bool +LayoutToNetlistStandardReader::test (const std::string &token) +{ + skip (); + return ! at_end () && m_ex.test (token.c_str ()); +} + +void +LayoutToNetlistStandardReader::expect (const std::string &token) +{ + m_ex.expect (token.c_str ()); +} + +void +LayoutToNetlistStandardReader::read_word_or_quoted (std::string &s) +{ + m_ex.read_word_or_quoted (s); +} + +int +LayoutToNetlistStandardReader::read_int () +{ + int i = 0; + m_ex.read (i); + return i; +} + +db::Coord +LayoutToNetlistStandardReader::read_coord () +{ + db::Coord i = 0; + m_ex.read (i); + return i; +} + +double +LayoutToNetlistStandardReader::read_double () +{ + double d = 0; + m_ex.read (d); + return d; +} + +bool +LayoutToNetlistStandardReader::at_end () +{ + return (m_ex.at_end () && m_stream.at_end ()); +} + +void +LayoutToNetlistStandardReader::skip () +{ + while (m_ex.at_end () || *m_ex.skip () == '#') { + if (m_stream.at_end ()) { + return; + } + m_line = m_stream.get_line (); + m_ex = tl::Extractor (m_line.c_str ()); + } +} + +void LayoutToNetlistStandardReader::read (db::LayoutToNetlist *l2n) +{ + try { + do_read (l2n); + } catch (tl::Exception &ex) { + throw tl::Exception (tl::sprintf (tl::to_string (tr ("%s in line: %d of %s")), ex.msg (), m_stream.line_number (), m_path)); + } +} + +void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n) +{ + int version = 0; + std::string description; + + // TODO: there probably is a more efficient way to force the layout inside l2n to be made + l2n->make_layer (std::string ()); + tl_assert (l2n->internal_layout ()); + + l2n->make_netlist (); + + Layers layers; + + while (! at_end ()) { + + if (test (skeys::version_key) || test (lkeys::version_key)) { + + Brace br (this); + version = read_int (); + br.done (); + + } else if (test (skeys::description_key) || test (lkeys::description_key)) { + + Brace br (this); + read_word_or_quoted (description); + br.done (); + + } else if (test (skeys::unit_key) || test (lkeys::unit_key)) { + + Brace br (this); + double dbu = read_double (); + l2n->internal_layout ()->dbu (dbu); + br.done (); + + } else if (test (skeys::top_key) || test (lkeys::top_key)) { + + Brace br (this); + std::string top; + read_word_or_quoted (top); + l2n->internal_layout ()->rename_cell (l2n->internal_top_cell ()->cell_index (), top.c_str ()); + br.done (); + + } else if (test (skeys::layer_key) || test (lkeys::layer_key)) { + + Brace br (this); + std::string layer; + read_word_or_quoted (layer); + layers.add (layer, l2n->make_layer (layer)); + br.done (); + + } else if (test (skeys::connect_key) || test (lkeys::connect_key)) { + + Brace br (this); + std::string l1; + read_word_or_quoted (l1); + while (br) { + std::string l2; + read_word_or_quoted (l2); + l2n->connect (layers.layer (l1), layers.layer (l2)); + } + br.done (); + + } else if (test (skeys::global_key) || test (lkeys::global_key)) { + + Brace br (this); + std::string l1; + read_word_or_quoted (l1); + while (br) { + std::string g; + read_word_or_quoted (g); + l2n->connect_global (layers.layer (l1), g); + } + br.done (); + + } else if (test (skeys::circuit_key) || test (lkeys::circuit_key)) { + + Brace br (this); + std::string name; + read_word_or_quoted (name); + + db::Circuit *circuit = new db::Circuit (); + circuit->set_name (name); + l2n->netlist ()->add_circuit (circuit); + + db::Layout *ly = l2n->internal_layout (); + db::cell_index_type ci = ly->add_cell (name.c_str ()); + circuit->set_cell_index (ci); + + std::map > connections; + + while (br) { + + if (test (skeys::net_key) || test (lkeys::net_key)) { + read_net (l2n, circuit, layers); + } else if (test (skeys::pin_key) || test (lkeys::pin_key)) { + read_pin (l2n, circuit); + } else if (test (skeys::device_key) || test (lkeys::device_key)) { + std::list conn; + db::CellInstArray ia = read_device (l2n, circuit, conn); + connections[ia] = conn; + } else if (test (skeys::circuit_key) || test (lkeys::circuit_key)) { + std::list conn; + db::CellInstArray ia = read_subcircuit (l2n, circuit, conn); + connections[ia] = conn; + } else { + throw tl::Exception (tl::to_string (tr ("Invalid keyword inside circuit definition (net, pin, device or circuit expected)"))); + } + + } + br.done (); + + db::Cell &ccell = ly->cell (ci); + + // connections needs to be made after the instances (because in a readonly Instances container + // the Instance pointers will invalidate when new instances are added) + for (db::Cell::const_iterator i = ccell.begin (); ! i.at_end (); ++i) { + std::map >::const_iterator c = connections.find (i->cell_inst ()); + if (c != connections.end ()) { + for (std::list::const_iterator j = c->second.begin (); j != c->second.end (); ++j) { + l2n->net_clusters ().clusters_per_cell (ci).add_connection (j->from_cluster, db::ClusterInstance (j->to_cluster, *i)); + } + } + } + + } else if (test (skeys::device_key) || test (lkeys::device_key)) { + + Brace br (this); + std::string name; + read_word_or_quoted (name); + + db::DeviceModel *dm = new db::DeviceModel (); + dm->set_name (name); + l2n->netlist ()->add_device_model (dm); + + db::cell_index_type ci = l2n->internal_layout ()->add_cell (name.c_str ()); + dm->set_cell_index (ci); + + std::string cls; + read_word_or_quoted (cls); + + db::DeviceClass *dc = 0; + for (db::Netlist::device_class_iterator i = l2n->netlist ()->begin_device_classes (); i != l2n->netlist ()->end_device_classes (); ++i) { + if (i->name () == cls) { + dc = i.operator-> (); + } + } + + // use a generic device class unless the right one is registered already. + bool gen_dc = (dc == 0); + if (gen_dc) { + dc = new db::DeviceClass (); + dc->set_name (cls); + l2n->netlist ()->add_device_class (dc); + } + + dm->set_device_class (dc); + + while (br) { + + if (test (skeys::terminal_key) || test (lkeys::terminal_key)) { + read_abstract_terminal (l2n, dm, gen_dc ? dc : 0, layers); + } else { + throw tl::Exception (tl::to_string (tr ("Invalid keyword inside device abstract definition (terminal expected)"))); + } + + } + + br.done (); + + } + + } +} + +std::pair +LayoutToNetlistStandardReader::read_geometry (db::LayoutToNetlist *l2n, Layers &layers) +{ + std::string lname; + + if (test (skeys::rect_key) || test (lkeys::rect_key)) { + + Brace br (this); + + read_word_or_quoted (lname); + unsigned int lid = l2n->layer_of (layers.layer (lname)); + + db::Coord l = read_coord (); + db::Coord b = read_coord (); + db::Coord r = read_coord (); + db::Coord t = read_coord (); + db::Box box (l, b, r, t); + + br.done (); + + return std::make_pair (lid, db::PolygonRef (db::Polygon (box), l2n->internal_layout ()->shape_repository ())); + + } else if (test (skeys::polygon_key) || test (lkeys::polygon_key)) { + + Brace br (this); + + read_word_or_quoted (lname); + unsigned int lid = l2n->layer_of (layers.layer (lname)); + + std::vector pt; + + while (br) { + db::Coord x = read_coord (); + db::Coord y = read_coord (); + pt.push_back (db::Point (x, y)); + } + + br.done (); + + db::Polygon poly; + poly.assign_hull (pt.begin (), pt.end ()); + return std::make_pair (lid, db::PolygonRef (poly, l2n->internal_layout ()->shape_repository ())); + + } else { + throw tl::Exception (tl::to_string (tr ("Invalid keyword inside net or terminal definition (polygon or rect expected)"))); + } +} + +void +LayoutToNetlistStandardReader::read_net (db::LayoutToNetlist *l2n, db::Circuit *circuit, Layers &layers) +{ + Brace br (this); + + std::string name; + read_word_or_quoted (name); + + db::Net *net = new db::Net (); + net->set_name (name); + circuit->add_net (net); + + db::connected_clusters &cc = l2n->net_clusters ().clusters_per_cell (circuit->cell_index ()); + db::local_cluster &lc = *cc.insert (); + net->set_cluster_id (lc.id ()); + + db::Cell &cell = l2n->internal_layout ()->cell (circuit->cell_index ()); + + while (br) { + std::pair pr = read_geometry (l2n, layers); + lc.add (pr.second, pr.first); + cell.shapes (pr.first).insert (pr.second); + } + + br.done (); +} + +void +LayoutToNetlistStandardReader::read_pin (db::LayoutToNetlist * /*l2n*/, db::Circuit *circuit) +{ + Brace br (this); + std::string name; + read_word_or_quoted (name); + std::string netname; + read_word_or_quoted (netname); + br.done (); + + const db::Pin &pin = circuit->add_pin (name); + + db::Net *net = circuit->net_by_name (netname); + if (!net) { + throw tl::Exception (tl::to_string (tr ("Not a valid net name: ")) + netname); + } + + circuit->connect_pin (pin.id (), net); +} + +db::CellInstArray +LayoutToNetlistStandardReader::read_device (db::LayoutToNetlist *l2n, db::Circuit *circuit, std::list &refs) +{ + Brace br (this); + + std::string name; + read_word_or_quoted (name); + + std::string dmname; + read_word_or_quoted (dmname); + + db::DeviceModel *dm = 0; + for (db::Netlist::device_model_iterator i = l2n->netlist ()->begin_device_models (); i != l2n->netlist ()->end_device_models (); ++i) { + if (i->name () == dmname) { + dm = i.operator-> (); + } + } + + if (! dm) { + throw tl::Exception (tl::to_string (tr ("Not a valid device model name: ")) + dmname); + } + + db::Device *device = new db::Device (); + device->set_device_class (const_cast (dm->device_class ())); + device->set_device_model (dm); + device->set_name (name); + circuit->add_device (device); + + db::Coord x = 0, y = 0; + + while (br) { + + if (test (skeys::location_key) || test (lkeys::location_key)) { + + Brace br2 (this); + x = read_coord (); + y = read_coord (); + br2.done (); + + } else if (test (skeys::terminal_key) || test (lkeys::terminal_key)) { + + Brace br2 (this); + std::string tname; + read_word_or_quoted (tname); + std::string netname; + read_word_or_quoted (netname); + br2.done (); + + size_t tid = std::numeric_limits::max (); + const std::vector &td = dm->device_class ()->terminal_definitions (); + for (std::vector::const_iterator t = td.begin (); t != td.end (); ++t) { + if (t->name () == tname) { + tid = t->id (); + break; + } + } + + if (tid == std::numeric_limits::max ()) { + throw tl::Exception (tl::to_string (tr ("Not a valid terminal name: ")) + tname + tl::to_string (tr (" for device class: ")) + dm->device_class ()->name ()); + } + + db::Net *net = circuit->net_by_name (netname); + if (!net) { + throw tl::Exception (tl::to_string (tr ("Not a valid net name: ")) + netname); + } + + device->connect_terminal (tid, net); + refs.push_back (Connections (net->cluster_id (), dm->cluster_id_for_terminal (tid))); + + } else if (test (skeys::param_key) || test (lkeys::param_key)) { + + Brace br2 (this); + std::string pname; + read_word_or_quoted (pname); + double value = read_double (); + br2.done (); + + size_t pid = std::numeric_limits::max (); + const std::vector &pd = dm->device_class ()->parameter_definitions (); + for (std::vector::const_iterator p = pd.begin (); p != pd.end (); ++p) { + if (p->name () == pname) { + pid = p->id (); + break; + } + } + + // if no parameter with this name exists, create one + if (pid == std::numeric_limits::max ()) { + // TODO: this should only happen for generic devices + db::DeviceClass *dc = const_cast (dm->device_class ()); + pid = dc->add_parameter_definition (db::DeviceParameterDefinition (pname, std::string ())).id (); + } + + device->set_parameter_value (pid, value); + + } else { + throw tl::Exception (tl::to_string (tr ("Invalid keyword inside device definition (location, param or terminal expected)"))); + } + + } + + double dbu = l2n->internal_layout ()->dbu (); + device->set_position (db::DPoint (dbu * x, dbu * y)); + + br.done (); + + // make device cell instance + db::CellInstArray inst (db::CellInst (dm->cell_index ()), db::Trans (db::Vector (x, y))); + db::Cell &ccell = l2n->internal_layout ()->cell (circuit->cell_index ()); + ccell.insert (inst); + + return inst; +} + +db::CellInstArray +LayoutToNetlistStandardReader::read_subcircuit (db::LayoutToNetlist *l2n, db::Circuit *circuit, std::list &refs) +{ + Brace br (this); + + std::string name; + read_word_or_quoted (name); + + std::string xname; + read_word_or_quoted (xname); + + db::Circuit *circuit_ref = l2n->netlist ()->circuit_by_name (xname); + if (! circuit_ref) { + throw tl::Exception (tl::to_string (tr ("Not a valid device circuit name: ")) + xname); + } + + db::SubCircuit *subcircuit = new db::SubCircuit (circuit_ref); + subcircuit->set_name (name); + circuit->add_subcircuit (subcircuit); + + db::Coord x = 0, y = 0; + bool mirror = false; + double angle = 0; + double mag = 1.0; + + db::InstElement ie; + bool inst_made = false; + + while (br) { + + if (test (skeys::location_key) || test (lkeys::location_key)) { + + Brace br2 (this); + x = read_coord (); + y = read_coord (); + br2.done (); + + if (inst_made) { + throw tl::Exception (tl::to_string (tr ("location key must come before pin key in subcircuit definition"))); + } + + } else if (test (skeys::rotation_key) || test (lkeys::rotation_key)) { + + Brace br2 (this); + angle = read_double (); + br2.done (); + + if (inst_made) { + throw tl::Exception (tl::to_string (tr ("rotation key must come before pin key in subcircuit definition"))); + } + + } else if (test (skeys::mirror_key) || test (lkeys::mirror_key)) { + + mirror = true; + if (inst_made) { + throw tl::Exception (tl::to_string (tr ("mirror key must come before pin key in subcircuit definition"))); + } + + } else if (test (skeys::scale_key) || test (lkeys::scale_key)) { + + Brace br2 (this); + mag = read_double (); + br2.done (); + + if (inst_made) { + throw tl::Exception (tl::to_string (tr ("scale key must come before pin key in subcircuit definition"))); + } + + } else if (test (skeys::pin_key) || test (lkeys::pin_key)) { + + Brace br2 (this); + std::string pname; + read_word_or_quoted (pname); + std::string netname; + read_word_or_quoted (netname); + br2.done (); + + const db::Pin *sc_pin = circuit_ref->pin_by_name (pname); + if (! sc_pin) { + throw tl::Exception (tl::to_string (tr ("Not a valid pin name: ")) + pname + tl::to_string (tr (" for circuit: ")) + circuit_ref->name ()); + } + + db::Net *net = circuit->net_by_name (netname); + if (!net) { + throw tl::Exception (tl::to_string (tr ("Not a valid net name: ")) + netname); + } + + subcircuit->connect_pin (sc_pin->id (), net); + db::Net *sc_net = circuit_ref->net_for_pin (sc_pin->id ()); + if (sc_net) { + refs.push_back (Connections (net->cluster_id (), sc_net->cluster_id ())); + } + + } else { + throw tl::Exception (tl::to_string (tr ("Invalid keyword inside subcircuit definition (location, rotation, mirror, scale or pin expected)"))); + } + + } + + br.done (); + + double dbu = l2n->internal_layout ()->dbu (); + subcircuit->set_trans (db::DCplxTrans (mag, angle, mirror, db::DVector (dbu * x, 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 ()); + ccell.insert (inst); + + return inst; +} + +void +LayoutToNetlistStandardReader::read_abstract_terminal (db::LayoutToNetlist *l2n, db::DeviceModel *dm, db::DeviceClass *dc, Layers &layers) +{ + Brace br (this); + + std::string name; + read_word_or_quoted (name); + + size_t tid = std::numeric_limits::max (); + const std::vector &td = dm->device_class ()->terminal_definitions (); + for (std::vector::const_iterator t = td.begin (); t != td.end (); ++t) { + if (t->name () == name) { + tid = t->id (); + break; + } + } + + // create a terminal unless one with this name already exists + if (tid == std::numeric_limits::max ()) { + if (! dc) { + throw tl::Exception (tl::to_string (tr ("Not a valid terminal name: ")) + name + tl::to_string (tr (" for device class: ")) + dm->device_class ()->name ()); + } + db::DeviceTerminalDefinition new_td (name, std::string ()); + tid = dc->add_terminal_definition (new_td).id (); + } + + db::connected_clusters &cc = l2n->net_clusters ().clusters_per_cell (dm->cell_index ()); + db::local_cluster &lc = *cc.insert (); + dm->set_cluster_id_for_terminal (tid, lc.id ()); + + db::Cell &cell = l2n->internal_layout ()->cell (dm->cell_index ()); + + while (br) { + std::pair pr = read_geometry (l2n, layers); + lc.add (pr.second, pr.first); + cell.shapes (pr.first).insert (pr.second); + } + + br.done (); +} } diff --git a/src/db/db/dbLayoutToNetlistReader.h b/src/db/db/dbLayoutToNetlistReader.h index 038820ac2..6fe9a566a 100644 --- a/src/db/db/dbLayoutToNetlistReader.h +++ b/src/db/db/dbLayoutToNetlistReader.h @@ -24,10 +24,83 @@ #define HDR_dbLayoutToNetlistReader #include "dbCommon.h" +#include "dbPolygon.h" +#include "dbCell.h" +#include "tlStream.h" namespace db { -// ... +namespace l2n_std_reader { + class Layers; + class Brace; +} + +class LayoutToNetlist; +class Circuit; +class Cell; +class DeviceModel; +class DeviceClass; + +/** + * @brief The base class for a LayoutToNetlist writer + */ +class DB_PUBLIC LayoutToNetlistReaderBase +{ +public: + LayoutToNetlistReaderBase () { } + virtual ~LayoutToNetlistReaderBase () { } + + virtual void read (db::LayoutToNetlist *l2n) = 0; +}; + +/** + * @brief The standard writer + */ +class DB_PUBLIC LayoutToNetlistStandardReader + : public LayoutToNetlistReaderBase +{ +public: + LayoutToNetlistStandardReader (tl::InputStream &stream); + + void read (db::LayoutToNetlist *l2n); + +private: + friend class l2n_std_reader::Brace; + typedef l2n_std_reader::Brace Brace; + typedef l2n_std_reader::Layers Layers; + + struct Connections + { + Connections (size_t _from_cluster, size_t _to_cluster) + : from_cluster (_from_cluster), to_cluster (_to_cluster) + { } + + size_t from_cluster, to_cluster; + }; + + tl::TextInputStream m_stream; + std::string m_path; + std::string m_line; + tl::Extractor m_ex; + + void do_read (db::LayoutToNetlist *l2n); + + bool test (const std::string &token); + void expect (const std::string &token); + void read_word_or_quoted(std::string &s); + int read_int (); + db::Coord read_coord (); + double read_double (); + bool at_end (); + void skip (); + + void read_net (db::LayoutToNetlist *l2n, db::Circuit *circuit, Layers &layers); + void read_pin (db::LayoutToNetlist *l2n, db::Circuit *circuit); + db::CellInstArray read_device (db::LayoutToNetlist *l2n, db::Circuit *circuit, std::list &refs); + db::CellInstArray read_subcircuit (db::LayoutToNetlist *l2n, db::Circuit *circuit, std::list &refs); + void read_abstract_terminal (db::LayoutToNetlist *l2n, db::DeviceModel *dm, db::DeviceClass *dc, Layers &layers); + std::pair read_geometry (db::LayoutToNetlist *l2n, Layers &layers); +}; } diff --git a/src/db/db/dbLayoutToNetlistWriter.cc b/src/db/db/dbLayoutToNetlistWriter.cc index b77bd8f1c..a84c9289c 100644 --- a/src/db/db/dbLayoutToNetlistWriter.cc +++ b/src/db/db/dbLayoutToNetlistWriter.cc @@ -22,107 +22,42 @@ #include "dbLayoutToNetlistWriter.h" #include "dbLayoutToNetlist.h" +#include "dbLayoutToNetlistFormatDefs.h" namespace db { +namespace l2n_std_format +{ // ------------------------------------------------------------------------------------------- -// LayoutToNetlistStandardWriter implementation +// std_writer_impl implementation -/** - * Comments are introduced by hash: # ... - * Names are words (alphanumerical plus "$", "_", ".") or enclosed in single or double quotes. - * Escape character is backslash. - * Separator is either , or whitespace. Keywords and names are case sensitive. - * Short keys are provided for compacter representation. Short keys can be - * non-alpha (e.g. "*") or empty. - * Single-valued attributes can be given without brackets. - * All dimensions are in units of database unit. - * The file follows the declaration-before-use principle - * (circuits before subcircuits, nets before use ...) - * - * Global statements: - * - * version() - file format version - * description() - an arbitrary description text - * unit() - specifies the database unit [short key: U] - * top() - specifies the name of the top circuit [short key: T] - * layer() - define a layer [short key: L] - * connect( ...) - connects layer1 with the following layers [short key: C] - * global( ...) - connects a layer with the given global nets [short key: G] - * circuit( [circuit-def]) - circuit (cell) [short key: X] - * device( [device-abstract-def]) - * - device abstract [short key: D] - * - * [circuit-def]: - * - * net( [geometry-def]) - net geometry [short key: N] - * A net declaration shall be there also if no geometry - * is present - * pin( ) - outgoing pin connection [short key: P] - * device( [device-def]) - * - device with connections [short key: D] - * subcircuit( [subcircuit-def]) - * - subcircuit with connections [short key: X] - * - * [geometry-def]: - * - * polygon( ...) - defines a polygon [short key: P] - * rect( ) - * - defines a rectangle [short key: R] - * - * [device-abstract-def]: - * - * terminal( [geometry-def]) - * - specifies the terminal geometry [short key: empty] - * - * [device-def]: - * - * param( ) - defines a parameter [short key P] - * abstract() - links to a geometrical device abstract on top level [short key A] - * terminal( ) - * - specifies connection of the terminal with - * a net (short key: empty) - * location( ) - location of the device [short key L] - * - * [subcircuit-def]: - * - * location( ) - location of the subcircuit [short key L] - * rotation() - rotation angle [short key O] - * mirror - if specified, the instance is mirrored before rotation [short key M] - * scale() - magnification [short key *] - * pin( ) - specifies connection of the pin with a net [short key: P] - */ +template +class std_writer_impl +{ +public: + std_writer_impl (tl::OutputStream &stream); -static std::string version_key ("version"); -static std::string description_key ("description"); -static std::string top_key ("top"); -static std::string unit_key ("unit"); -static std::string layer_key ("layer"); -static std::string text_key ("text"); -static std::string connect_key ("connect"); -static std::string global_key ("global"); -static std::string circuit_key ("circuit"); -static std::string net_key ("net"); -static std::string device_key ("device"); -static std::string subcircuit_key ("subcircuit"); -static std::string polygon_key ("polygon"); -static std::string rect_key ("rect"); -static std::string terminal_key ("terminal"); -static std::string abstract_key ("abstract"); -static std::string label_key ("label"); -static std::string param_key ("param"); -static std::string location_key ("location"); -static std::string rotation_key ("rotation"); -static std::string mirror_key ("mirror"); -static std::string scale_key ("scale"); -static std::string pin_key ("pin"); -static std::string indent1 (" "); -static std::string indent2 (" "); -static std::string endl ("\n"); + void write (const db::LayoutToNetlist *l2n); -LayoutToNetlistStandardWriter::LayoutToNetlistStandardWriter (tl::OutputStream &stream) +private: + tl::OutputStream *mp_stream; + + void write (const db::LayoutToNetlist *l2n, const db::Circuit &circuit); + void write (const db::LayoutToNetlist *l2n, const db::Net &net); + void write (const db::LayoutToNetlist *l2n, const db::SubCircuit &subcircuit); + void write (const db::LayoutToNetlist *l2n, const db::Device &device); + void write (const db::LayoutToNetlist *l2n, const db::DeviceModel &device_model); + void write (const db::PolygonRef *s, const db::ICplxTrans &tr, const std::string &lname); +}; + +static const std::string endl ("\n"); +static const std::string indent1 (" "); +static const std::string indent2 (" "); + +template +std_writer_impl::std_writer_impl (tl::OutputStream &stream) : mp_stream (&stream) { // .. nothing yet .. @@ -138,7 +73,8 @@ static std::string name_for_layer (const db::Layout *layout, unsigned int l) } } -void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n) +template +void std_writer_impl::write (const db::LayoutToNetlist *l2n) { bool any = false; @@ -150,17 +86,17 @@ void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n) *mp_stream << "# General section" << endl; *mp_stream << "# Lists general definitions." << endl << endl; if (version > 0) { - *mp_stream << version_key << "(" << version << ")" << endl; + *mp_stream << Keys::version_key << "(" << version << ")" << endl; } - *mp_stream << top_key << "(" << tl::to_word_or_quoted_string (ly->cell_name (l2n->internal_top_cell ()->cell_index ())) << ")" << endl; - *mp_stream << unit_key << "(" << ly->dbu () << ")" << endl; + *mp_stream << Keys::top_key << "(" << tl::to_word_or_quoted_string (ly->cell_name (l2n->internal_top_cell ()->cell_index ())) << ")" << endl; + *mp_stream << Keys::unit_key << "(" << ly->dbu () << ")" << endl; *mp_stream << endl << "# Layer section" << endl; *mp_stream << "# This section lists the mask layers (drawing or derived) and their connections." << endl; *mp_stream << endl << "# Mask layers" << endl; for (db::Connectivity::layer_iterator l = l2n->connectivity ().begin_layers (); l != l2n->connectivity ().end_layers (); ++l) { - *mp_stream << layer_key << "(" << name_for_layer (ly, *l) << ")" << endl; + *mp_stream << Keys::layer_key << "(" << name_for_layer (ly, *l) << ")" << endl; } *mp_stream << endl << "# Mask layer connectivity" << endl; @@ -169,7 +105,7 @@ void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n) db::Connectivity::layer_iterator ce = l2n->connectivity ().end_connected (*l); db::Connectivity::layer_iterator cb = l2n->connectivity ().begin_connected (*l); if (cb != ce) { - *mp_stream << connect_key << "(" << name_for_layer (ly, *l); + *mp_stream << Keys::connect_key << "(" << name_for_layer (ly, *l); for (db::Connectivity::layer_iterator c = l2n->connectivity ().begin_connected (*l); c != ce; ++c) { *mp_stream << " " << name_for_layer (ly, *c); } @@ -188,7 +124,7 @@ void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n) *mp_stream << endl << "# Global nets and connectivity" << endl; any = true; } - *mp_stream << global_key << "(" << name_for_layer (ly, *l); + *mp_stream << Keys::global_key << "(" << name_for_layer (ly, *l); for (db::Connectivity::global_nets_iterator g = gb; g != ge; ++g) { *mp_stream << " " << tl::to_word_or_quoted_string (l2n->connectivity ().global_net_name (*g)); } @@ -203,7 +139,7 @@ void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n) } for (db::Netlist::const_device_model_iterator m = nl->begin_device_models (); m != nl->end_device_models (); ++m) { if (m->device_class ()) { - *mp_stream << device_key << "(" << tl::to_word_or_quoted_string (m->name ()) << " " << tl::to_word_or_quoted_string (m->device_class ()->name ()) << endl; + *mp_stream << Keys::device_key << "(" << tl::to_word_or_quoted_string (m->name ()) << " " << tl::to_word_or_quoted_string (m->device_class ()->name ()) << endl; write (l2n, *m); *mp_stream << ")" << endl; } @@ -211,16 +147,17 @@ void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n) *mp_stream << endl << "# Circuit section" << endl; *mp_stream << "# Circuits are the hierarchical building blocks of the netlist." << endl; - for (db::Netlist::const_top_down_circuit_iterator i = nl->begin_top_down (); i != nl->end_top_down (); ++i) { + for (db::Netlist::const_bottom_up_circuit_iterator i = nl->begin_bottom_up (); i != nl->end_bottom_up (); ++i) { const db::Circuit *x = *i; *mp_stream << endl << "# Circuit " << x->name () << endl; - *mp_stream << circuit_key << "(" << tl::to_word_or_quoted_string (x->name ()) << endl; + *mp_stream << Keys::circuit_key << "(" << tl::to_word_or_quoted_string (x->name ()) << endl; write (l2n, *x); *mp_stream << ")" << endl; } } -void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n, const db::Circuit &circuit) +template +void std_writer_impl::write (const db::LayoutToNetlist *l2n, const db::Circuit &circuit) { if (circuit.begin_nets () != circuit.end_nets ()) { *mp_stream << endl << indent1 << "# Nets with their geometries" << endl; @@ -234,7 +171,7 @@ void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n, const for (db::Circuit::const_pin_iterator p = circuit.begin_pins (); p != circuit.end_pins (); ++p) { const db::Net *net = circuit.net_for_pin (p->id ()); if (net) { - *mp_stream << indent1 << pin_key << "(" << tl::to_word_or_quoted_string (p->expanded_name ()) << " " << tl::to_word_or_quoted_string (net->expanded_name ()) << ")" << endl; + *mp_stream << indent1 << Keys::pin_key << "(" << tl::to_word_or_quoted_string (p->expanded_name ()) << " " << tl::to_word_or_quoted_string (net->expanded_name ()) << ")" << endl; } } } @@ -265,7 +202,8 @@ void write_points (tl::OutputStream &stream, const T &poly, const Tr &tr) } } -void LayoutToNetlistStandardWriter::write (const db::PolygonRef *s, const db::ICplxTrans &tr, const std::string &lname) +template +void std_writer_impl::write (const db::PolygonRef *s, const db::ICplxTrans &tr, const std::string &lname) { db::ICplxTrans t = tr * db::ICplxTrans (s->trans ()); @@ -273,14 +211,14 @@ void LayoutToNetlistStandardWriter::write (const db::PolygonRef *s, const db::IC if (poly.is_box ()) { db::Box box = t * poly.box (); - *mp_stream << rect_key << "(" << lname; + *mp_stream << Keys::rect_key << "(" << lname; *mp_stream << " " << box.left () << " " << box.bottom (); *mp_stream << " " << box.right () << " " << box.top (); *mp_stream << ")"; } else { - *mp_stream << polygon_key << "(" << lname; + *mp_stream << Keys::polygon_key << "(" << lname; if (poly.holes () > 0) { db::SimplePolygon sp (poly); write_points (*mp_stream, sp, t); @@ -292,7 +230,8 @@ void LayoutToNetlistStandardWriter::write (const db::PolygonRef *s, const db::IC } } -void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n, const db::Net &net) +template +void std_writer_impl::write (const db::LayoutToNetlist *l2n, const db::Net &net) { const db::Layout *ly = l2n->internal_layout (); const db::hier_clusters &clusters = l2n->net_clusters (); @@ -319,7 +258,7 @@ void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n, const } else { if (! any) { - *mp_stream << indent1 << net_key << "(" << tl::to_word_or_quoted_string (net.expanded_name ()) << endl; + *mp_stream << indent1 << Keys::net_key << "(" << tl::to_word_or_quoted_string (net.expanded_name ()) << endl; any = true; } @@ -340,28 +279,30 @@ void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n, const if (any) { *mp_stream << indent1 << ")" << endl; } else { - *mp_stream << indent1 << net_key << "(" << tl::to_word_or_quoted_string (net.expanded_name ()) << ")" << endl; + *mp_stream << indent1 << Keys::net_key << "(" << tl::to_word_or_quoted_string (net.expanded_name ()) << ")" << endl; } } -void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n, const db::SubCircuit &subcircuit) +template +void std_writer_impl::write (const db::LayoutToNetlist *l2n, const db::SubCircuit &subcircuit) { const db::Layout *ly = l2n->internal_layout (); double dbu = ly->dbu (); - *mp_stream << indent1 << subcircuit_key << "(" << tl::to_word_or_quoted_string (subcircuit.expanded_name ()); + *mp_stream << indent1 << Keys::circuit_key << "(" << tl::to_word_or_quoted_string (subcircuit.expanded_name ()); + *mp_stream << " " << tl::to_word_or_quoted_string (subcircuit.circuit_ref ()->name ()); const db::DCplxTrans &tr = subcircuit.trans (); if (tr.is_mag ()) { - *mp_stream << " " << scale_key << "(" << tr.mag () << ")"; + *mp_stream << " " << Keys::scale_key << "(" << tr.mag () << ")"; } if (tr.is_mirror ()) { - *mp_stream << " " << mirror_key; + *mp_stream << " " << Keys::mirror_key; } if (fabs (tr.angle ()) > 1e-6) { - *mp_stream << " " << rotation_key << "(" << tr.angle () << ")"; + *mp_stream << " " << Keys::rotation_key << "(" << tr.angle () << ")"; } - *mp_stream << " " << location_key << "(" << tr.disp ().x () / dbu << " " << tr.disp ().y () / dbu << ")"; + *mp_stream << " " << Keys::location_key << "(" << tr.disp ().x () / dbu << " " << tr.disp ().y () / dbu << ")"; // each pin in one line for more than a few pins bool separate_lines = (subcircuit.circuit_ref ()->pin_count () > 1); @@ -378,7 +319,7 @@ void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n, const } else { *mp_stream << " "; } - *mp_stream << pin_key << "(" << tl::to_word_or_quoted_string (p->expanded_name ()) << " " << tl::to_word_or_quoted_string (net->expanded_name ()) << ")"; + *mp_stream << Keys::pin_key << "(" << tl::to_word_or_quoted_string (p->expanded_name ()) << " " << tl::to_word_or_quoted_string (net->expanded_name ()) << ")"; if (separate_lines) { *mp_stream << endl; } @@ -392,7 +333,8 @@ void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n, const *mp_stream << ")" << endl; } -void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n, const db::DeviceModel &device_model) +template +void std_writer_impl::write (const db::LayoutToNetlist *l2n, const db::DeviceModel &device_model) { const std::vector &td = device_model.device_class ()->terminal_definitions (); @@ -402,7 +344,7 @@ void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n, const for (std::vector::const_iterator t = td.begin (); t != td.end (); ++t) { - *mp_stream << indent1 << terminal_key << "(" << t->name () << endl; + *mp_stream << indent1 << Keys::terminal_key << "(" << t->name () << endl; for (db::Connectivity::layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) { @@ -422,31 +364,55 @@ void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n, const } } -void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n, const db::Device &device) +template +void std_writer_impl::write (const db::LayoutToNetlist *l2n, const db::Device &device) { const db::Layout *ly = l2n->internal_layout (); double dbu = ly->dbu (); - *mp_stream << indent1 << device_key << "(" << tl::to_word_or_quoted_string (device.expanded_name ()); - *mp_stream << " " << tl::to_word_or_quoted_string (device.device_class ()->name ()) << endl; + *mp_stream << indent1 << Keys::device_key << "(" << tl::to_word_or_quoted_string (device.expanded_name ()); - *mp_stream << indent2 << location_key << "(" << device.position ().x () / dbu << " " << device.position ().y () / dbu << ")" << endl; + tl_assert (device.device_model () != 0); + *mp_stream << " " << tl::to_word_or_quoted_string (device.device_model ()->name ()) << endl; - if (device.device_model ()) { - *mp_stream << indent2 << abstract_key << "(" << tl::to_word_or_quoted_string (device.device_model ()->name ()) << ")" << endl; - } + *mp_stream << indent2 << Keys::location_key << "(" << device.position ().x () / dbu << " " << device.position ().y () / dbu << ")" << endl; const std::vector &pd = device.device_class ()->parameter_definitions (); for (std::vector::const_iterator i = pd.begin (); i != pd.end (); ++i) { - *mp_stream << indent2 << param_key << "(" << tl::to_word_or_quoted_string (i->name ()) << " " << device.parameter_value (i->id ()) << ")" << endl; + *mp_stream << indent2 << Keys::param_key << "(" << tl::to_word_or_quoted_string (i->name ()) << " " << device.parameter_value (i->id ()) << ")" << endl; } const std::vector &td = device.device_class ()->terminal_definitions (); for (std::vector::const_iterator i = td.begin (); i != td.end (); ++i) { - *mp_stream << indent2 << terminal_key << "(" << tl::to_word_or_quoted_string (i->name ()) << " " << tl::to_word_or_quoted_string (device.net_for_terminal (i->id ())->expanded_name ()) << ")" << endl; + const db::Net *net = device.net_for_terminal (i->id ()); + if (net) { + *mp_stream << indent2 << Keys::terminal_key << "(" << tl::to_word_or_quoted_string (i->name ()) << " " << tl::to_word_or_quoted_string (net->expanded_name ()) << ")" << endl; + } } *mp_stream << indent1 << ")" << endl; } } + +// ------------------------------------------------------------------------------------------- +// LayoutToNetlistStandardWriter implementation + +LayoutToNetlistStandardWriter::LayoutToNetlistStandardWriter (tl::OutputStream &stream, bool short_version) + : mp_stream (&stream), m_short_version (short_version) +{ + // .. nothing yet .. +} + +void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n) +{ + if (m_short_version) { + l2n_std_format::std_writer_impl > writer (*mp_stream); + writer.write (l2n); + } else { + l2n_std_format::std_writer_impl > writer (*mp_stream); + writer.write (l2n); + } +} + +} diff --git a/src/db/db/dbLayoutToNetlistWriter.h b/src/db/db/dbLayoutToNetlistWriter.h index 47ad24102..117cf62a3 100644 --- a/src/db/db/dbLayoutToNetlistWriter.h +++ b/src/db/db/dbLayoutToNetlistWriter.h @@ -24,18 +24,12 @@ #define HDR_dbLayoutToNetlistWriter #include "dbCommon.h" -#include "dbPolygon.h" #include "tlStream.h" namespace db { class LayoutToNetlist; -class Net; -class Circuit; -class SubCircuit; -class Device; -class DeviceModel; /** * @brief The base class for a LayoutToNetlist writer @@ -56,19 +50,13 @@ class DB_PUBLIC LayoutToNetlistStandardWriter : public LayoutToNetlistWriterBase { public: - LayoutToNetlistStandardWriter (tl::OutputStream &stream); + LayoutToNetlistStandardWriter (tl::OutputStream &stream, bool short_version); void write (const db::LayoutToNetlist *l2n); private: tl::OutputStream *mp_stream; - - void write (const db::LayoutToNetlist *l2n, const db::Circuit &circuit); - void write (const db::LayoutToNetlist *l2n, const db::Net &net); - void write (const db::LayoutToNetlist *l2n, const db::SubCircuit &subcircuit); - void write (const db::LayoutToNetlist *l2n, const db::Device &device); - void write (const db::LayoutToNetlist *l2n, const db::DeviceModel &device_model); - void write (const db::PolygonRef *s, const db::ICplxTrans &tr, const std::string &lname); + bool m_short_version; }; } diff --git a/src/db/db/dbNetlistDeviceExtractor.cc b/src/db/db/dbNetlistDeviceExtractor.cc index 87db486d6..19b1a4803 100644 --- a/src/db/db/dbNetlistDeviceExtractor.cc +++ b/src/db/db/dbNetlistDeviceExtractor.cc @@ -307,20 +307,16 @@ void NetlistDeviceExtractor::push_new_devices () ps.insert (std::make_pair (m_terminal_id_propname_id, tl::Variant (t->first))); db::properties_id_type pi = mp_layout->properties_repository ().properties_id (ps); - // initialize the local cluster (will not be extracted) - db::local_cluster *lc = cc.insert (); - lc->add_attr (pi); - dm->set_cluster_id_for_terminal (t->first, lc->id ()); - - // build the cell shapes and local cluster + // build the cell shapes for (geometry_per_layer_type::const_iterator l = t->second.begin (); l != t->second.end (); ++l) { + db::Shapes &shapes = device_cell.shapes (l->first); for (std::vector::const_iterator s = l->second.begin (); s != l->second.end (); ++s) { db::PolygonRef pr = *s; pr.transform (db::PolygonRef::trans_type (-disp)); shapes.insert (db::PolygonRefWithProperties (pr, pi)); - lc->add (*s, l->first); } + } } diff --git a/src/db/db/dbNetlistExtractor.cc b/src/db/db/dbNetlistExtractor.cc index 8f88932e2..e4881f0db 100644 --- a/src/db/db/dbNetlistExtractor.cc +++ b/src/db/db/dbNetlistExtractor.cc @@ -63,18 +63,44 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, const db::Connect circuits.insert (std::make_pair (c->cell_index (), c.operator-> ())); } + // reverse lookup for DeviceModel vs. cell index + std::map device_models; + for (db::Netlist::device_model_iterator dm = nl.begin_device_models (); dm != nl.end_device_models (); ++dm) { + device_models.insert (std::make_pair (dm->cell_index (), dm.operator-> ())); + } + std::map > pins_per_cluster_per_cell; for (db::Layout::bottom_up_const_iterator cid = mp_layout->begin_bottom_up (); cid != mp_layout->end_bottom_up (); ++cid) { - if (db::NetlistDeviceExtractor::is_device_cell (*mp_layout, *cid)) { - continue; - } - const connected_clusters_type &clusters = mp_clusters->clusters_per_cell (*cid); if (clusters.empty ()) { continue; } + std::map::const_iterator dmc = device_models.find (*cid); + if (dmc != device_models.end ()) { + + // make the terminal to cluster ID connections for the device model from the device cells + + if (m_terminal_annot_name_id.first) { + + for (connected_clusters_type::const_iterator dc = clusters.begin (); dc != clusters.end (); ++dc) { + for (local_cluster_type::attr_iterator a = dc->begin_attr (); a != dc->end_attr (); ++a) { + const db::PropertiesRepository::properties_set &ps = mp_layout->properties_repository ().properties (*a); + for (db::PropertiesRepository::properties_set::const_iterator j = ps.begin (); j != ps.end (); ++j) { + if (j->first == m_terminal_annot_name_id.second) { + dmc->second->set_cluster_id_for_terminal (j->second.to (), dc->id ()); + } + } + } + } + + } + + continue; + + } + // a cell makes a new circuit (or uses an existing one) db::Circuit *circuit = 0; diff --git a/src/db/db/gsiDeclDbLayoutToNetlist.cc b/src/db/db/gsiDeclDbLayoutToNetlist.cc index 3ba88b8c7..c8c0eb80d 100644 --- a/src/db/db/gsiDeclDbLayoutToNetlist.cc +++ b/src/db/db/gsiDeclDbLayoutToNetlist.cc @@ -60,10 +60,10 @@ static void build_all_nets (const db::LayoutToNetlist *l2n, const db::CellMappin l2n->build_all_nets (cmap, target, lmap, net_cell_name_prefix.is_nil () ? 0 : np.c_str (), circuit_cell_name_prefix.is_nil () ? 0 : cp.c_str (), device_cell_name_prefix.is_nil () ? 0 : dp.c_str ()); } -static void write_l2n (const db::LayoutToNetlist *l2n, const std::string &path) +static void write_l2n (const db::LayoutToNetlist *l2n, const std::string &path, bool short_format) { tl::OutputStream stream (path); - db::LayoutToNetlistStandardWriter writer (stream); + db::LayoutToNetlistStandardWriter writer (stream, short_format); writer.write (l2n); } @@ -277,7 +277,7 @@ Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist", "This variant accepts a database-unit location. The location is given in the\n" "coordinate space of the initial cell.\n" ) + - gsi::method_ext ("write", &write_l2n, gsi::arg ("path"), + gsi::method_ext ("write", &write_l2n, gsi::arg ("path"), gsi::arg ("short_format", false), "@brief Writes the extracted netlist to a file.\n" "This method employs the native format of KLayout.\n" ), diff --git a/src/db/unit_tests/dbLayoutToNetlistReaderTests.cc b/src/db/unit_tests/dbLayoutToNetlistReaderTests.cc new file mode 100644 index 000000000..9e37f997a --- /dev/null +++ b/src/db/unit_tests/dbLayoutToNetlistReaderTests.cc @@ -0,0 +1,66 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2019 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include "dbLayoutToNetlist.h" +#include "dbLayoutToNetlistReader.h" +#include "dbLayoutToNetlistWriter.h" +#include "dbStream.h" +#include "dbCommonReader.h" +#include "dbNetlistDeviceExtractorClasses.h" + +#include "tlUnitTest.h" +#include "tlStream.h" +#include "tlFileUtils.h" + +TEST(1_ReaderBasic) +{ + db::Layout ly; + + db::Cell &tc = ly.cell (ly.add_cell ("TOP")); + db::LayoutToNetlist l2n (db::RecursiveShapeIterator (ly, tc, std::set ())); + + std::string in_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au.txt"); + tl::InputStream is_in (in_path); + + db::LayoutToNetlistStandardReader reader (is_in); + reader.read (&l2n); + + // verify against the input + + std::string path = tmp_file ("tmp_l2nreader_1.txt"); + { + tl::OutputStream stream (path); + db::LayoutToNetlistStandardWriter writer (stream, false); + writer.write (&l2n); + } + + std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au.txt"); + + tl::InputStream is (path); + tl::InputStream is_au (au_path); + + if (is.read_all () != is_au.read_all ()) { + _this->raise (tl::sprintf ("Compare failed - see\n actual: %s\n golden: %s", + tl::absolute_file_path (path), + tl::absolute_file_path (au_path))); + } +} diff --git a/src/db/unit_tests/dbLayoutToNetlistWriterTests.cc b/src/db/unit_tests/dbLayoutToNetlistWriterTests.cc index 4484d10a6..195f9b2c2 100644 --- a/src/db/unit_tests/dbLayoutToNetlistWriterTests.cc +++ b/src/db/unit_tests/dbLayoutToNetlistWriterTests.cc @@ -168,7 +168,7 @@ TEST(1_WriterBasic) std::string path = tmp_file ("tmp_l2nwriter_1.txt"); { tl::OutputStream stream (path); - db::LayoutToNetlistStandardWriter writer (stream); + db::LayoutToNetlistStandardWriter writer (stream, false); writer.write (&l2n); } diff --git a/src/db/unit_tests/unit_tests.pro b/src/db/unit_tests/unit_tests.pro index 5bed164ca..460b684a1 100644 --- a/src/db/unit_tests/unit_tests.pro +++ b/src/db/unit_tests/unit_tests.pro @@ -64,7 +64,8 @@ SOURCES = \ dbNetlistDeviceExtractorTests.cc \ dbNetlistDeviceClassesTests.cc \ dbLayoutToNetlistTests.cc \ - dbLayoutToNetlistWriterTests.cc + dbLayoutToNetlistWriterTests.cc \ + dbLayoutToNetlistReaderTests.cc INCLUDEPATH += $$TL_INC $$DB_INC $$GSI_INC DEPENDPATH += $$TL_INC $$DB_INC $$GSI_INC diff --git a/testdata/algo/l2n_writer_au.txt b/testdata/algo/l2n_writer_au.txt index c8f789c19..7329fa2ce 100644 --- a/testdata/algo/l2n_writer_au.txt +++ b/testdata/algo/l2n_writer_au.txt @@ -37,10 +37,10 @@ connect(nsd diff_cont nsd) # Device abstracts list the pin shapes of the devices. device(D$PMOS PMOS terminal(S - rect(poly -125 -475 125 475) + rect(psd -650 -475 -125 475) ) terminal(G - rect(psd -650 -475 -125 475) + rect(poly -125 -475 125 475) ) terminal(D rect(psd 125 -475 675 475) @@ -48,10 +48,10 @@ device(D$PMOS PMOS ) device(D$PMOS$1 PMOS terminal(S - rect(poly -125 -475 125 475) + rect(psd -675 -475 -125 475) ) terminal(G - rect(psd -675 -475 -125 475) + rect(poly -125 -475 125 475) ) terminal(D rect(psd 125 -475 650 475) @@ -59,10 +59,10 @@ device(D$PMOS$1 PMOS ) device(D$NMOS NMOS terminal(S - rect(poly -125 -475 125 475) + rect(nsd -650 -475 -125 475) ) terminal(G - rect(nsd -650 -475 -125 475) + rect(poly -125 -475 125 475) ) terminal(D rect(nsd 125 -475 675 475) @@ -70,10 +70,10 @@ device(D$NMOS NMOS ) device(D$NMOS$1 NMOS terminal(S - rect(poly -125 -475 125 475) + rect(nsd -675 -475 -125 475) ) terminal(G - rect(nsd -675 -475 -125 475) + rect(poly -125 -475 125 475) ) terminal(D rect(nsd 125 -475 650 475) @@ -83,6 +83,135 @@ device(D$NMOS$1 NMOS # Circuit section # Circuits are the hierarchical building blocks of the netlist. +# Circuit INV2 +circuit(INV2 + + # Nets with their geometries + net(IN + rect(poly -525 -250 -275 2250) + rect(poly -1700 1620 -400 1980) + rect(poly -525 -800 -275 800) + rect(poly -525 -475 -275 475) + rect(poly -525 2000 -275 3600) + rect(poly -525 2325 -275 3275) + rect(poly_lbl -801 1799 -799 1801) + rect(poly_cont -1630 1690 -1410 1910) + ) + net($2 + rect(poly 275 -250 525 2250) + rect(poly 220 820 580 1180) + rect(poly 275 2000 525 3600) + rect(poly 275 2325 525 3275) + rect(poly 275 -800 525 800) + rect(poly 275 -475 525 475) + rect(diff_cont -910 2490 -690 2710) + rect(diff_cont -910 2890 -690 3110) + rect(diff_cont -910 -310 -690 -90) + rect(diff_cont -910 90 -690 310) + rect(poly_cont 290 890 510 1110) + rect(metal1 -800 820 580 1180) + rect(metal1 -980 -420 -620 2420) + rect(metal1 -980 2420 -620 3180) + rect(metal1 -980 -380 -620 380) + rect(psd -1050 2325 -525 3275) + rect(psd -1050 2325 -525 3275) + rect(nsd -1050 -475 -525 475) + rect(nsd -1050 -475 -525 475) + ) + net(OUT + rect(diff_cont 690 2890 910 3110) + rect(diff_cont 690 2490 910 2710) + rect(diff_cont 690 90 910 310) + rect(diff_cont 690 -310 910 -90) + polygon(metal1 800 20 800 380 940 380 940 1620 620 1620 620 2420 980 2420 980 1980 1300 1980 1300 20) + rect(metal1 620 2420 980 3180) + rect(metal1 620 -380 980 380) + rect(metal1_lbl 799 1799 801 1801) + rect(psd 525 2325 1050 3275) + rect(psd 525 2325 1050 3275) + rect(nsd 525 -475 1050 475) + rect(nsd 525 -475 1050 475) + ) + net($4 + rect(diff_cont -110 -310 110 -90) + rect(diff_cont -110 90 110 310) + rect(diff_cont -110 90 110 310) + rect(diff_cont -110 -310 110 -90) + rect(metal1 -180 -380 180 380) + rect(metal1 -180 -380 180 380) + rect(via1 -125 -325 125 -75) + rect(via1 -125 75 125 325) + rect(metal2 -1400 -450 1400 450) + rect(nsd -275 -475 275 475) + rect(nsd -275 -475 275 475) + rect(nsd -275 -475 275 475) + ) + net($5 + rect(diff_cont -110 2490 110 2710) + rect(diff_cont -110 2890 110 3110) + rect(diff_cont -110 2890 110 3110) + rect(diff_cont -110 2490 110 2710) + rect(metal1 -180 2420 180 3180) + rect(metal1 -180 2420 180 3180) + rect(via1 -125 2475 125 2725) + rect(via1 -125 2875 125 3125) + rect(metal2 -1400 2350 1400 3250) + rect(psd -275 2325 275 3275) + rect(psd -275 2325 275 3275) + rect(psd -275 2325 275 3275) + ) + + # Outgoing pins and their connections to nets + pin(IN IN) + pin($1 $2) + pin(OUT OUT) + pin($3 $4) + pin($4 $5) + + # Devices and their connections + device($1 D$PMOS + location(-400 2800) + param(L 0.25) + param(W 0.95) + param(AS 0.49875) + param(AD 0.26125) + terminal(S $2) + terminal(G IN) + terminal(D $5) + ) + device($2 D$PMOS$1 + location(400 2800) + param(L 0.25) + param(W 0.95) + param(AS 0.26125) + param(AD 0.49875) + terminal(S $5) + terminal(G $2) + terminal(D OUT) + ) + device($3 D$NMOS + location(-400 0) + param(L 0.25) + param(W 0.95) + param(AS 0.49875) + param(AD 0.26125) + terminal(S $2) + terminal(G IN) + terminal(D $4) + ) + device($4 D$NMOS$1 + location(400 0) + param(L 0.25) + param(W 0.95) + param(AS 0.26125) + param(AD 0.49875) + terminal(S $4) + terminal(G $2) + terminal(D OUT) + ) + +) + # Circuit RINGO circuit(RINGO @@ -280,61 +409,61 @@ circuit(RINGO ) # Subcircuits and their connections - subcircuit($1 location(23760 0) + circuit($1 INV2 location(23760 0) pin(IN $I8) pin($1 FB) pin($3 VSS) pin($4 VDD) ) - subcircuit($2 location(0 0) + circuit($2 INV2 location(0 0) pin(IN FB) pin(OUT $I19) pin($3 VSS) pin($4 VDD) ) - subcircuit($3 location(2640 0) + circuit($3 INV2 location(2640 0) pin(IN $I19) pin(OUT $I1) pin($3 VSS) pin($4 VDD) ) - subcircuit($4 location(5280 0) + circuit($4 INV2 location(5280 0) pin(IN $I1) pin(OUT $I2) pin($3 VSS) pin($4 VDD) ) - subcircuit($5 location(7920 0) + circuit($5 INV2 location(7920 0) pin(IN $I2) pin(OUT $I3) pin($3 VSS) pin($4 VDD) ) - subcircuit($6 location(10560 0) + circuit($6 INV2 location(10560 0) pin(IN $I3) pin(OUT $I4) pin($3 VSS) pin($4 VDD) ) - subcircuit($7 location(13200 0) + circuit($7 INV2 location(13200 0) pin(IN $I4) pin(OUT $I5) pin($3 VSS) pin($4 VDD) ) - subcircuit($8 location(15840 0) + circuit($8 INV2 location(15840 0) pin(IN $I5) pin(OUT $I6) pin($3 VSS) pin($4 VDD) ) - subcircuit($9 location(18480 0) + circuit($9 INV2 location(18480 0) pin(IN $I6) pin(OUT $I7) pin($3 VSS) pin($4 VDD) ) - subcircuit($10 location(21120 0) + circuit($10 INV2 location(21120 0) pin(IN $I7) pin(OUT $I8) pin($3 VSS) @@ -342,136 +471,3 @@ circuit(RINGO ) ) - -# Circuit INV2 -circuit(INV2 - - # Nets with their geometries - net(IN - rect(poly -525 -250 -275 2250) - rect(poly -1700 1620 -400 1980) - rect(poly -525 -800 -275 800) - rect(poly -525 -475 -275 475) - rect(poly -525 2000 -275 3600) - rect(poly -525 2325 -275 3275) - rect(poly_lbl -801 1799 -799 1801) - rect(poly_cont -1630 1690 -1410 1910) - ) - net($2 - rect(poly 275 -250 525 2250) - rect(poly 220 820 580 1180) - rect(poly 275 2000 525 3600) - rect(poly 275 2325 525 3275) - rect(poly 275 -800 525 800) - rect(poly 275 -475 525 475) - rect(diff_cont -910 2490 -690 2710) - rect(diff_cont -910 2890 -690 3110) - rect(diff_cont -910 -310 -690 -90) - rect(diff_cont -910 90 -690 310) - rect(poly_cont 290 890 510 1110) - rect(metal1 -800 820 580 1180) - rect(metal1 -980 -420 -620 2420) - rect(metal1 -980 2420 -620 3180) - rect(metal1 -980 -380 -620 380) - rect(psd -1050 2325 -525 3275) - rect(psd -1050 2325 -525 3275) - rect(nsd -1050 -475 -525 475) - rect(nsd -1050 -475 -525 475) - ) - net(OUT - rect(diff_cont 690 2890 910 3110) - rect(diff_cont 690 2490 910 2710) - rect(diff_cont 690 90 910 310) - rect(diff_cont 690 -310 910 -90) - polygon(metal1 800 20 800 380 940 380 940 1620 620 1620 620 2420 980 2420 980 1980 1300 1980 1300 20) - rect(metal1 620 2420 980 3180) - rect(metal1 620 -380 980 380) - rect(metal1_lbl 799 1799 801 1801) - rect(psd 525 2325 1050 3275) - rect(psd 525 2325 1050 3275) - rect(nsd 525 -475 1050 475) - rect(nsd 525 -475 1050 475) - ) - net($4 - rect(diff_cont -110 -310 110 -90) - rect(diff_cont -110 90 110 310) - rect(diff_cont -110 90 110 310) - rect(diff_cont -110 -310 110 -90) - rect(metal1 -180 -380 180 380) - rect(metal1 -180 -380 180 380) - rect(via1 -125 -325 125 -75) - rect(via1 -125 75 125 325) - rect(metal2 -1400 -450 1400 450) - rect(nsd -275 -475 275 475) - rect(nsd -275 -475 275 475) - rect(nsd -275 -475 275 475) - ) - net($5 - rect(diff_cont -110 2490 110 2710) - rect(diff_cont -110 2890 110 3110) - rect(diff_cont -110 2890 110 3110) - rect(diff_cont -110 2490 110 2710) - rect(metal1 -180 2420 180 3180) - rect(metal1 -180 2420 180 3180) - rect(via1 -125 2475 125 2725) - rect(via1 -125 2875 125 3125) - rect(metal2 -1400 2350 1400 3250) - rect(psd -275 2325 275 3275) - rect(psd -275 2325 275 3275) - rect(psd -275 2325 275 3275) - ) - - # Outgoing pins and their connections to nets - pin(IN IN) - pin($1 $2) - pin(OUT OUT) - pin($3 $4) - pin($4 $5) - - # Devices and their connections - device($1 PMOS - location(-400 2800) - abstract(D$PMOS) - param(L 0.25) - param(W 0.95) - param(AS 0.49875) - param(AD 0.26125) - terminal(S $2) - terminal(G IN) - terminal(D $5) - ) - device($2 PMOS - location(400 2800) - abstract(D$PMOS$1) - param(L 0.25) - param(W 0.95) - param(AS 0.26125) - param(AD 0.49875) - terminal(S $5) - terminal(G $2) - terminal(D OUT) - ) - device($3 NMOS - location(-400 0) - abstract(D$NMOS) - param(L 0.25) - param(W 0.95) - param(AS 0.49875) - param(AD 0.26125) - terminal(S $2) - terminal(G IN) - terminal(D $4) - ) - device($4 NMOS - location(400 0) - abstract(D$NMOS$1) - param(L 0.25) - param(W 0.95) - param(AS 0.26125) - param(AD 0.49875) - terminal(S $4) - terminal(G $2) - terminal(D OUT) - ) - -)