diff --git a/src/db/db/dbHierNetworkProcessor.cc b/src/db/db/dbHierNetworkProcessor.cc index 2f41ea28e..fb2ea01f1 100644 --- a/src/db/db/dbHierNetworkProcessor.cc +++ b/src/db/db/dbHierNetworkProcessor.cc @@ -2029,6 +2029,27 @@ recursive_cluster_shape_iterator &recursive_cluster_shape_iterator::operat return *this; } +template +void recursive_cluster_shape_iterator::skip_cell () +{ + m_shape_iter = typename db::local_cluster::shape_iterator (); + + do { + + up (); + if (m_conn_iter_stack.empty ()) { + return; + } + + ++m_conn_iter_stack.back ().first; + + } while (m_conn_iter_stack.back ().first == m_conn_iter_stack.back ().second); + + while (m_shape_iter.at_end () && ! m_conn_iter_stack.empty ()) { + next_conn (); + } +} + template void recursive_cluster_shape_iterator::next_conn () { diff --git a/src/db/db/dbHierNetworkProcessor.h b/src/db/db/dbHierNetworkProcessor.h index d4211f9ce..535d18752 100644 --- a/src/db/db/dbHierNetworkProcessor.h +++ b/src/db/db/dbHierNetworkProcessor.h @@ -882,6 +882,11 @@ public: */ recursive_cluster_shape_iterator &operator++ (); + /** + * @brief Skips the current cell and advances to the next cell and shape + */ + void skip_cell (); + private: typedef typename db::connected_clusters::connections_type connections_type; diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index 773a47c1e..8d8a89381 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -78,28 +78,43 @@ size_t LayoutToNetlist::max_vertex_count () const return m_dss.max_vertex_count (); } -db::Region *LayoutToNetlist::make_layer (unsigned int layer_index) +db::Region *LayoutToNetlist::make_layer (unsigned int layer_index, const std::string &n) { db::RecursiveShapeIterator si (m_iter); si.set_layer (layer_index); si.shape_flags (db::ShapeIterator::All); - return new db::Region (si, m_dss); + + db::Region *region = new db::Region (si, m_dss); + if (! n.empty ()) { + name (*region, n); + } + return region; } -db::Region *LayoutToNetlist::make_text_layer (unsigned int layer_index) +db::Region *LayoutToNetlist::make_text_layer (unsigned int layer_index, const std::string &n) { db::RecursiveShapeIterator si (m_iter); si.set_layer (layer_index); si.shape_flags (db::ShapeIterator::Texts); - return new db::Region (si, m_dss); + + db::Region *region = new db::Region (si, m_dss); + if (! n.empty ()) { + name (*region, n); + } + return region; } -db::Region *LayoutToNetlist::make_polygon_layer (unsigned int layer_index) +db::Region *LayoutToNetlist::make_polygon_layer (unsigned int layer_index, const std::string &n) { db::RecursiveShapeIterator si (m_iter); si.set_layer (layer_index); si.shape_flags (db::ShapeIterator::Paths | db::ShapeIterator::Polygons | db::ShapeIterator::Boxes); - return new db::Region (si, m_dss); + + db::Region *region = new db::Region (si, m_dss); + if (! n.empty ()) { + name (*region, n); + } + return region; } void LayoutToNetlist::extract_devices (db::NetlistDeviceExtractor &extractor, const std::map &layers) @@ -202,6 +217,15 @@ const db::Cell *LayoutToNetlist::internal_top_cell () const return &m_dss.const_initial_cell (); } +void LayoutToNetlist::name (const db::Region ®ion, const std::string &name) +{ + unsigned int li = layer_of (region); + db::Layout &ly = m_dss.layout (); + db::LayerProperties lp = ly.get_properties (li); + lp.name = name; + ly.set_properties (li, lp); +} + unsigned int LayoutToNetlist::layer_of (const db::Region ®ion) const { const db::DeepRegion *dr = dynamic_cast (region.delegate ()); diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h index d2f5649e8..df01397c1 100644 --- a/src/db/db/dbLayoutToNetlist.h +++ b/src/db/db/dbLayoutToNetlist.h @@ -114,6 +114,25 @@ public: */ size_t max_vertex_count () const; + /** + * @brief Names a layer + * This is a formal name for the layer. Using a name or layer properties + * (see below) enhances readability of backannotated information + * if layers are involved. Use this method or the other variants to + * attach a name or standard layer properties to a region delivered + * by "make_layer" or derived from other regions through boolean + * operations. + */ + void name (const db::Region ®ion, const std::string &name); + + /** + * @brief Gets the name of the given layer + */ + std::string name (const db::Region ®ion) const + { + return internal_layout ()->get_properties (layer_of (region)).name; + } + /** * @brief Creates a new region representing an original layer * "layer_index" is the layer index of the desired layer in the original layout. @@ -122,19 +141,19 @@ public: * A variant not taking texts is "make_polygon_layer". A Variant only taking * texts is "make_text_layer". */ - db::Region *make_layer (unsigned int layer_index); + db::Region *make_layer (unsigned int layer_index, const std::string &name = std::string ()); /** * @brief Creates a new region representing an original layer taking texts only * See "make_layer" for details. */ - db::Region *make_text_layer (unsigned int layer_index); + db::Region *make_text_layer (unsigned int layer_index, const std::string &name = std::string ()); /** * @brief Creates a new region representing an original layer taking polygons and texts * See "make_layer" for details. */ - db::Region *make_polygon_layer (unsigned int layer_index); + db::Region *make_polygon_layer (unsigned int layer_index, const std::string &name = std::string ()); /** * @brief Extracts devices diff --git a/src/db/db/dbLayoutToNetlistWriter.cc b/src/db/db/dbLayoutToNetlistWriter.cc index 0c824e1f4..b77bd8f1c 100644 --- a/src/db/db/dbLayoutToNetlistWriter.cc +++ b/src/db/db/dbLayoutToNetlistWriter.cc @@ -52,8 +52,8 @@ namespace db * 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-footprint-def]) - * - device footprint [short key: D] + * device( [device-abstract-def]) + * - device abstract [short key: D] * * [circuit-def]: * @@ -72,7 +72,7 @@ namespace db * rect( ) * - defines a rectangle [short key: R] * - * [device-footprint-def]: + * [device-abstract-def]: * * terminal( [geometry-def]) * - specifies the terminal geometry [short key: empty] @@ -80,7 +80,7 @@ namespace db * [device-def]: * * param( ) - defines a parameter [short key P] - * footprint() - links to a geometrical device footprint on top level [short key F] + * 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) @@ -110,7 +110,7 @@ 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 footprint_key ("footprint"); +static std::string abstract_key ("abstract"); static std::string label_key ("label"); static std::string param_key ("param"); static std::string location_key ("location"); @@ -140,20 +140,31 @@ static std::string name_for_layer (const db::Layout *layout, unsigned int l) void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n) { - const int version = 1; + bool any = false; + + const int version = 0; const db::Layout *ly = l2n->internal_layout (); const db::Netlist *nl = l2n->netlist (); - *mp_stream << "# General" << endl; - *mp_stream << version_key << "(" << version << ")" << endl; + *mp_stream << "# General section" << endl; + *mp_stream << "# Lists general definitions." << endl << endl; + if (version > 0) { + *mp_stream << 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 << endl << "# Layers" << endl; - for (db::Connectivity::layer_iterator l = l2n->connectivity ().begin_layers (); l != l2n->connectivity ().end_layers (); ++l) { + *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 << endl << "# Mask layer connectivity" << endl; + for (db::Connectivity::layer_iterator l = l2n->connectivity ().begin_layers (); l != l2n->connectivity ().end_layers (); ++l) { db::Connectivity::layer_iterator ce = l2n->connectivity ().end_connected (*l); db::Connectivity::layer_iterator cb = l2n->connectivity ().begin_connected (*l); @@ -165,9 +176,18 @@ void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n) *mp_stream << ")" << endl; } + } + + any = false; + for (db::Connectivity::layer_iterator l = l2n->connectivity ().begin_layers (); l != l2n->connectivity ().end_layers (); ++l) { + db::Connectivity::global_nets_iterator ge = l2n->connectivity ().end_global_connections (*l); db::Connectivity::global_nets_iterator gb = l2n->connectivity ().begin_global_connections (*l); if (gb != ge) { + if (! any) { + *mp_stream << endl << "# Global nets and connectivity" << endl; + any = true; + } *mp_stream << 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)); @@ -177,7 +197,10 @@ void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n) } - *mp_stream << endl << "# Device footprints" << endl; + if (nl->begin_device_models () != nl->end_device_models ()) { + *mp_stream << endl << "# Device abstracts section" << endl; + *mp_stream << "# Device abstracts list the pin shapes of the devices." << endl; + } 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; @@ -186,6 +209,8 @@ 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) { const db::Circuit *x = *i; *mp_stream << endl << "# Circuit " << x->name () << endl; @@ -197,24 +222,38 @@ void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n) void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n, const db::Circuit &circuit) { - for (db::Circuit::const_net_iterator n = circuit.begin_nets (); n != circuit.end_nets (); ++n) { - write (l2n, *n); - } - - 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; + if (circuit.begin_nets () != circuit.end_nets ()) { + *mp_stream << endl << indent1 << "# Nets with their geometries" << endl; + for (db::Circuit::const_net_iterator n = circuit.begin_nets (); n != circuit.end_nets (); ++n) { + write (l2n, *n); } } - for (db::Circuit::const_device_iterator d = circuit.begin_devices (); d != circuit.end_devices (); ++d) { - write (l2n, *d); + if (circuit.begin_pins () != circuit.end_pins ()) { + *mp_stream << endl << indent1 << "# Outgoing pins and their connections to nets" << endl; + 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; + } + } } - for (db::Circuit::const_subcircuit_iterator x = circuit.begin_subcircuits (); x != circuit.end_subcircuits (); ++x) { - write (l2n, *x); + if (circuit.begin_devices () != circuit.end_devices ()) { + *mp_stream << endl << indent1 << "# Devices and their connections" << endl; + for (db::Circuit::const_device_iterator d = circuit.begin_devices (); d != circuit.end_devices (); ++d) { + write (l2n, *d); + } } + + if (circuit.begin_subcircuits () != circuit.end_subcircuits ()) { + *mp_stream << endl << indent1 << "# Subcircuits and their connections" << endl; + for (db::Circuit::const_subcircuit_iterator x = circuit.begin_subcircuits (); x != circuit.end_subcircuits (); ++x) { + write (l2n, *x); + } + } + + *mp_stream << endl; } template @@ -226,12 +265,14 @@ void write_points (tl::OutputStream &stream, const T &poly, const Tr &tr) } } -void LayoutToNetlistStandardWriter::write (const db::PolygonRef *s, const std::string &lname) +void LayoutToNetlistStandardWriter::write (const db::PolygonRef *s, const db::ICplxTrans &tr, const std::string &lname) { + db::ICplxTrans t = tr * db::ICplxTrans (s->trans ()); + const db::Polygon &poly = s->obj (); if (poly.is_box ()) { - db::Box box = s->trans () * poly.box (); + db::Box box = t * poly.box (); *mp_stream << rect_key << "(" << lname; *mp_stream << " " << box.left () << " " << box.bottom (); *mp_stream << " " << box.right () << " " << box.top (); @@ -242,9 +283,9 @@ void LayoutToNetlistStandardWriter::write (const db::PolygonRef *s, const std::s *mp_stream << polygon_key << "(" << lname; if (poly.holes () > 0) { db::SimplePolygon sp (poly); - write_points (*mp_stream, sp, s->trans ()); + write_points (*mp_stream, sp, t); } else { - write_points (*mp_stream, poly, s->trans ()); + write_points (*mp_stream, poly, t); } *mp_stream << ")"; @@ -262,18 +303,36 @@ void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n, const for (db::Connectivity::layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) { - const db::local_cluster &lc = clusters.clusters_per_cell (circuit->cell_index ()).cluster_by_id (net.cluster_id ()); - for (db::local_cluster::shape_iterator s = lc.begin (*l); ! s.at_end (); ++s) { + db::cell_index_type cci = circuit->cell_index (); + db::cell_index_type prev_ci = cci; + + for (db::recursive_cluster_shape_iterator si (clusters, *l, cci, net.cluster_id ()); ! si.at_end (); ) { + + // 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 && l2n->netlist ()->circuit_by_cell_index (ci)) { + + si.skip_cell (); + + } else { + + if (! any) { + *mp_stream << indent1 << net_key << "(" << tl::to_word_or_quoted_string (net.expanded_name ()) << endl; + any = true; + } + + *mp_stream << indent2; + write (si.operator-> (), si.trans (), name_for_layer (ly, *l)); + *mp_stream << endl; + + prev_ci = ci; + + ++si; - if (! any) { - *mp_stream << indent1 << net_key << "(" << tl::to_word_or_quoted_string (net.expanded_name ()) << endl; - any = true; } - *mp_stream << indent2; - write (s.operator-> (), name_for_layer (ly, *l)); - *mp_stream << endl; - } } @@ -341,21 +400,25 @@ void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n, const const db::hier_clusters &clusters = l2n->net_clusters (); const db::Connectivity &conn = l2n->connectivity (); - for (db::Connectivity::layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) { + for (std::vector::const_iterator t = td.begin (); t != td.end (); ++t) { - for (std::vector::const_iterator t = td.begin (); t != td.end (); ++t) { + *mp_stream << indent1 << terminal_key << "(" << t->name () << endl; + + for (db::Connectivity::layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) { const db::local_cluster &lc = clusters.clusters_per_cell (device_model.cell_index ()).cluster_by_id (device_model.cluster_id_for_terminal (t->id ())); for (db::local_cluster::shape_iterator s = lc.begin (*l); ! s.at_end (); ++s) { - *mp_stream << indent1; - write (s.operator-> (), name_for_layer (ly, *l)); + *mp_stream << indent2; + write (s.operator-> (), db::ICplxTrans (), name_for_layer (ly, *l)); *mp_stream << endl; } } + *mp_stream << indent1 << ")" << endl; + } } @@ -370,7 +433,7 @@ void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n, const *mp_stream << indent2 << location_key << "(" << device.position ().x () / dbu << " " << device.position ().y () / dbu << ")" << endl; if (device.device_model ()) { - *mp_stream << indent2 << footprint_key << "(" << tl::to_word_or_quoted_string (device.device_model ()->name ()) << ")" << endl; + *mp_stream << indent2 << abstract_key << "(" << tl::to_word_or_quoted_string (device.device_model ()->name ()) << ")" << endl; } const std::vector &pd = device.device_class ()->parameter_definitions (); diff --git a/src/db/db/dbLayoutToNetlistWriter.h b/src/db/db/dbLayoutToNetlistWriter.h index 2955ba66b..47ad24102 100644 --- a/src/db/db/dbLayoutToNetlistWriter.h +++ b/src/db/db/dbLayoutToNetlistWriter.h @@ -68,7 +68,7 @@ private: 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 std::string &lname); + void write (const db::PolygonRef *s, const db::ICplxTrans &tr, const std::string &lname); }; } diff --git a/src/db/db/gsiDeclDbLayoutToNetlist.cc b/src/db/db/gsiDeclDbLayoutToNetlist.cc index 3974dddc5..3ba88b8c7 100644 --- a/src/db/db/gsiDeclDbLayoutToNetlist.cc +++ b/src/db/db/gsiDeclDbLayoutToNetlist.cc @@ -95,21 +95,34 @@ Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist", gsi::method ("max_vertex_count", &db::LayoutToNetlist::max_vertex_count, "See \\max_vertex_count= for details about this attribute." ) + - gsi::method ("make_layer", &db::LayoutToNetlist::make_layer, gsi::arg ("layer_index"), - "@brief Creates a new region representing an original layer\n" - "'layer_index'' is the layer index of the desired layer in the original layout.\n" - "The Region object returned is a new object and must be deleted by the caller.\n" + gsi::method ("name", &db::LayoutToNetlist::name, gsi::arg ("l"), + "@brief Names the given layer\n" + "'l' must be a hierarchical region derived with \\make_layer, \\make_text_layer or \\make_polygon_layer or " + "a region derived from those by boolean operations or other hierarchical operations.\n" + "\n" + "Naming a layer allows the system to indicate the layer in various contexts, i.e. " + "when writing the data to a file.\n" + ) + + gsi::method ("make_layer", &db::LayoutToNetlist::make_layer, gsi::arg ("layer_index"), gsi::arg ("name", std::string ()), + "@brief Creates a new hierarchical region representing an original layer\n" + "'layer_index' is the layer index of the desired layer in the original layout.\n" "This variant produces polygons and takes texts for net name annotation.\n" "A variant not taking texts is \\make_polygon_layer. A Variant only taking\n" - "texts is \\make_text_layer.\n""" + "texts is \\make_text_layer.\n" + "\n" + "The name is optional. If given, the layer will already be named accordingly (see \\name).\n" ) + - gsi::method ("make_text_layer", &db::LayoutToNetlist::make_text_layer, gsi::arg ("layer_index"), + gsi::method ("make_text_layer", &db::LayoutToNetlist::make_text_layer, gsi::arg ("layer_index"), gsi::arg ("name", std::string ()), "@brief Creates a new region representing an original layer taking texts only\n" "See \\make_layer for details.\n" + "\n" + "The name is optional. If given, the layer will already be named accordingly (see \\name).\n" ) + - gsi::method ("make_polygon_layer", &db::LayoutToNetlist::make_polygon_layer, gsi::arg ("layer_index"), + gsi::method ("make_polygon_layer", &db::LayoutToNetlist::make_polygon_layer, gsi::arg ("layer_index"), gsi::arg ("name", std::string ()), "@brief Creates a new region representing an original layer taking polygons and texts\n" "See \\make_layer for details.\n" + "\n" + "The name is optional. If given, the layer will already be named accordingly (see \\name).\n" ) + gsi::method ("extract_devices", &db::LayoutToNetlist::extract_devices, gsi::arg ("extractor"), gsi::arg ("layers"), "@brief Extracts devices\n" diff --git a/src/db/unit_tests/dbHierNetworkProcessorTests.cc b/src/db/unit_tests/dbHierNetworkProcessorTests.cc index 337780a04..c81cc404b 100644 --- a/src/db/unit_tests/dbHierNetworkProcessorTests.cc +++ b/src/db/unit_tests/dbHierNetworkProcessorTests.cc @@ -702,10 +702,14 @@ static std::string path2string (const db::Layout &ly, db::cell_index_type ci, co return res; } -static std::string rcsiter2string (const db::Layout &ly, db::cell_index_type ci, db::recursive_cluster_shape_iterator si) +static std::string rcsiter2string (const db::Layout &ly, db::cell_index_type ci, db::recursive_cluster_shape_iterator si, db::cell_index_type ci2skip = std::numeric_limits::max ()) { std::string res; while (! si.at_end ()) { + if (si.cell_index () == ci2skip) { + si.skip_cell (); + continue; + } db::Polygon poly = si->obj (); poly.transform (si->trans ()); poly.transform (si.trans ()); @@ -766,6 +770,16 @@ TEST(41_HierClustersRecursiveClusterShapeIterator) } EXPECT_EQ (n, 1); EXPECT_EQ (res, "TOP:(0,0;0,1000;1000,1000;1000,0);TOP/C1:(0,10;0,510;2000,510;2000,10);TOP/C2:(0,30;0,2030;500,2030;500,30);TOP/C2/C1:(0,50;0,550;2000,550;2000,50)"); + + res.clear (); + n = 0; + cluster = &hc.clusters_per_cell (top.cell_index ()); + for (db::connected_clusters::const_iterator i = cluster->begin (); i != cluster->end (); ++i) { + res = rcsiter2string (ly, top.cell_index (), db::recursive_cluster_shape_iterator (hc, l1, top.cell_index (), i->id ()), c1.cell_index ()); + ++n; + } + EXPECT_EQ (n, 1); + EXPECT_EQ (res, "TOP:(0,0;0,1000;1000,1000;1000,0);TOP/C2:(0,30;0,2030;500,2030;500,30)"); } TEST(41_HierClustersRecursiveClusterIterator) diff --git a/src/db/unit_tests/dbLayoutToNetlistWriterTests.cc b/src/db/unit_tests/dbLayoutToNetlistWriterTests.cc index 0213af5dd..4484d10a6 100644 --- a/src/db/unit_tests/dbLayoutToNetlistWriterTests.cc +++ b/src/db/unit_tests/dbLayoutToNetlistWriterTests.cc @@ -72,27 +72,33 @@ TEST(1_WriterBasic) db::Cell &tc = ly.cell (*ly.begin_top_down ()); db::LayoutToNetlist l2n (db::RecursiveShapeIterator (ly, tc, std::set ())); - std::auto_ptr rnwell (l2n.make_layer (nwell)); - std::auto_ptr ractive (l2n.make_layer (active)); - std::auto_ptr rpoly (l2n.make_polygon_layer (poly)); - std::auto_ptr rpoly_lbl (l2n.make_text_layer (poly_lbl)); - std::auto_ptr rdiff_cont (l2n.make_polygon_layer (diff_cont)); - std::auto_ptr rpoly_cont (l2n.make_polygon_layer (poly_cont)); - std::auto_ptr rmetal1 (l2n.make_polygon_layer (metal1)); - std::auto_ptr rmetal1_lbl (l2n.make_text_layer (metal1_lbl)); - std::auto_ptr rvia1 (l2n.make_polygon_layer (via1)); - std::auto_ptr rmetal2 (l2n.make_polygon_layer (metal2)); - std::auto_ptr rmetal2_lbl (l2n.make_text_layer (metal2_lbl)); + std::auto_ptr rnwell (l2n.make_layer (nwell, "nwell")); + std::auto_ptr ractive (l2n.make_layer (active, "active")); + std::auto_ptr rpoly (l2n.make_polygon_layer (poly, "poly")); + std::auto_ptr rpoly_lbl (l2n.make_text_layer (poly_lbl, "poly_lbl")); + std::auto_ptr rdiff_cont (l2n.make_polygon_layer (diff_cont, "diff_cont")); + std::auto_ptr rpoly_cont (l2n.make_polygon_layer (poly_cont, "poly_cont")); + std::auto_ptr rmetal1 (l2n.make_polygon_layer (metal1, "metal1")); + std::auto_ptr rmetal1_lbl (l2n.make_text_layer (metal1_lbl, "metal1_lbl")); + std::auto_ptr rvia1 (l2n.make_polygon_layer (via1, "via1")); + std::auto_ptr rmetal2 (l2n.make_polygon_layer (metal2, "metal2")); + std::auto_ptr rmetal2_lbl (l2n.make_text_layer (metal2_lbl, "metal2_lbl")); // derived regions db::Region rpactive = *ractive & *rnwell; db::Region rpgate = rpactive & *rpoly; db::Region rpsd = rpactive - rpgate; + l2n.name (rpactive, "pactive"); + l2n.name (rpgate, "pgate"); + l2n.name (rpsd, "psd"); db::Region rnactive = *ractive - *rnwell; db::Region rngate = rnactive & *rpoly; db::Region rnsd = rnactive - rngate; + l2n.name (rnactive, "nactive"); + l2n.name (rngate, "ngate"); + l2n.name (rnsd, "nsd"); db::NetlistDeviceExtractorMOS3Transistor pmos_ex ("PMOS"); db::NetlistDeviceExtractorMOS3Transistor nmos_ex ("NMOS"); @@ -157,18 +163,23 @@ TEST(1_WriterBasic) rpoly_lbl.reset (0); l2n.extract_netlist (); + l2n.netlist ()->purge (); - tl::OutputMemoryStream mem; + std::string path = tmp_file ("tmp_l2nwriter_1.txt"); { - tl::OutputStream stream (mem); + tl::OutputStream stream (path); db::LayoutToNetlistStandardWriter writer (stream); writer.write (&l2n); } -// TODO: too big for inlined text ... -#if 0 - EXPECT_EQ (std::string (mem.data (), mem.size ()), - "" - ); -#endif + 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/testdata/algo/l2n_writer_au.txt b/testdata/algo/l2n_writer_au.txt new file mode 100644 index 000000000..c8f789c19 --- /dev/null +++ b/testdata/algo/l2n_writer_au.txt @@ -0,0 +1,477 @@ +# General section +# Lists general definitions. + +top(RINGO) +unit(0.001) + +# Layer section +# This section lists the mask layers (drawing or derived) and their connections. + +# Mask layers +layer(poly) +layer(poly_lbl) +layer(diff_cont) +layer(poly_cont) +layer(metal1) +layer(metal1_lbl) +layer(via1) +layer(metal2) +layer(metal2_lbl) +layer(psd) +layer(nsd) + +# Mask layer connectivity +connect(poly poly poly_lbl poly_cont) +connect(poly_lbl poly) +connect(diff_cont diff_cont metal1 psd 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(psd diff_cont psd) +connect(nsd diff_cont nsd) + +# Device abstracts section +# Device abstracts list the pin shapes of the devices. +device(D$PMOS PMOS + terminal(S + rect(poly -125 -475 125 475) + ) + terminal(G + rect(psd -650 -475 -125 475) + ) + terminal(D + rect(psd 125 -475 675 475) + ) +) +device(D$PMOS$1 PMOS + terminal(S + rect(poly -125 -475 125 475) + ) + terminal(G + rect(psd -675 -475 -125 475) + ) + terminal(D + rect(psd 125 -475 650 475) + ) +) +device(D$NMOS NMOS + terminal(S + rect(poly -125 -475 125 475) + ) + terminal(G + rect(nsd -650 -475 -125 475) + ) + terminal(D + rect(nsd 125 -475 675 475) + ) +) +device(D$NMOS$1 NMOS + terminal(S + rect(poly -125 -475 125 475) + ) + terminal(G + rect(nsd -675 -475 -125 475) + ) + terminal(D + rect(nsd 125 -475 650 475) + ) +) + +# Circuit section +# Circuits are the hierarchical building blocks of the netlist. + +# Circuit RINGO +circuit(RINGO + + # Nets with their geometries + net(FB + rect(diff_cont 22850 2490 23070 2710) + rect(diff_cont 22850 2890 23070 3110) + rect(diff_cont 22850 -310 23070 -90) + rect(diff_cont 22850 90 23070 310) + rect(metal1 -1700 1620 -1340 1980) + rect(via1 -1645 1675 -1395 1925) + rect(via1 22835 1675 23085 1925) + rect(metal2 -1720 1600 23160 2000) + rect(metal2_lbl -1 1799 1 1801) + ) + net(VSS + rect(diff_cont 2530 -310 2750 -90) + rect(diff_cont 2530 90 2750 310) + rect(diff_cont 2530 90 2750 310) + rect(diff_cont 2530 -310 2750 -90) + 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(diff_cont 5170 -310 5390 -90) + rect(diff_cont 5170 90 5390 310) + rect(diff_cont 5170 90 5390 310) + rect(diff_cont 5170 -310 5390 -90) + rect(diff_cont 7810 -310 8030 -90) + rect(diff_cont 7810 90 8030 310) + rect(diff_cont 7810 90 8030 310) + rect(diff_cont 7810 -310 8030 -90) + rect(diff_cont 10450 -310 10670 -90) + rect(diff_cont 10450 90 10670 310) + rect(diff_cont 10450 90 10670 310) + rect(diff_cont 10450 -310 10670 -90) + rect(diff_cont 13090 -310 13310 -90) + rect(diff_cont 13090 90 13310 310) + rect(diff_cont 13090 90 13310 310) + rect(diff_cont 13090 -310 13310 -90) + rect(diff_cont 15730 -310 15950 -90) + rect(diff_cont 15730 90 15950 310) + rect(diff_cont 15730 90 15950 310) + rect(diff_cont 15730 -310 15950 -90) + rect(diff_cont 18370 -310 18590 -90) + rect(diff_cont 18370 90 18590 310) + rect(diff_cont 18370 90 18590 310) + rect(diff_cont 18370 -310 18590 -90) + rect(diff_cont 21010 -310 21230 -90) + rect(diff_cont 21010 90 21230 310) + rect(diff_cont 21010 90 21230 310) + rect(diff_cont 21010 -310 21230 -90) + rect(diff_cont 23650 -310 23870 -90) + rect(diff_cont 23650 90 23870 310) + rect(diff_cont 23650 90 23870 310) + rect(diff_cont 23650 -310 23870 -90) + rect(metal1 2460 -380 2820 380) + rect(metal1 2460 -380 2820 380) + rect(metal1 -180 -380 180 380) + rect(metal1 -180 -380 180 380) + rect(metal1 5100 -380 5460 380) + rect(metal1 5100 -380 5460 380) + rect(metal1 7740 -380 8100 380) + rect(metal1 7740 -380 8100 380) + rect(metal1 10380 -380 10740 380) + rect(metal1 10380 -380 10740 380) + rect(metal1 13020 -380 13380 380) + rect(metal1 13020 -380 13380 380) + rect(metal1 15660 -380 16020 380) + rect(metal1 15660 -380 16020 380) + rect(metal1 18300 -380 18660 380) + rect(metal1 18300 -380 18660 380) + rect(metal1 20940 -380 21300 380) + rect(metal1 20940 -380 21300 380) + rect(metal1 23580 -380 23940 380) + rect(metal1 23580 -380 23940 380) + rect(metal2_lbl -1 -1 1 1) + ) + net(VDD + rect(diff_cont 2530 2490 2750 2710) + rect(diff_cont 2530 2890 2750 3110) + rect(diff_cont 2530 2890 2750 3110) + rect(diff_cont 2530 2490 2750 2710) + 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(diff_cont 5170 2490 5390 2710) + rect(diff_cont 5170 2890 5390 3110) + rect(diff_cont 5170 2890 5390 3110) + rect(diff_cont 5170 2490 5390 2710) + rect(diff_cont 7810 2490 8030 2710) + rect(diff_cont 7810 2890 8030 3110) + rect(diff_cont 7810 2890 8030 3110) + rect(diff_cont 7810 2490 8030 2710) + rect(diff_cont 10450 2490 10670 2710) + rect(diff_cont 10450 2890 10670 3110) + rect(diff_cont 10450 2890 10670 3110) + rect(diff_cont 10450 2490 10670 2710) + rect(diff_cont 13090 2490 13310 2710) + rect(diff_cont 13090 2890 13310 3110) + rect(diff_cont 13090 2890 13310 3110) + rect(diff_cont 13090 2490 13310 2710) + rect(diff_cont 15730 2490 15950 2710) + rect(diff_cont 15730 2890 15950 3110) + rect(diff_cont 15730 2890 15950 3110) + rect(diff_cont 15730 2490 15950 2710) + rect(diff_cont 18370 2490 18590 2710) + rect(diff_cont 18370 2890 18590 3110) + rect(diff_cont 18370 2890 18590 3110) + rect(diff_cont 18370 2490 18590 2710) + rect(diff_cont 21010 2490 21230 2710) + rect(diff_cont 21010 2890 21230 3110) + rect(diff_cont 21010 2890 21230 3110) + rect(diff_cont 21010 2490 21230 2710) + rect(diff_cont 23650 2490 23870 2710) + rect(diff_cont 23650 2890 23870 3110) + rect(diff_cont 23650 2890 23870 3110) + rect(diff_cont 23650 2490 23870 2710) + rect(metal1 2460 2420 2820 3180) + rect(metal1 2460 2420 2820 3180) + rect(metal1 -180 2420 180 3180) + rect(metal1 -180 2420 180 3180) + rect(metal1 5100 2420 5460 3180) + rect(metal1 5100 2420 5460 3180) + rect(metal1 7740 2420 8100 3180) + rect(metal1 7740 2420 8100 3180) + rect(metal1 10380 2420 10740 3180) + rect(metal1 10380 2420 10740 3180) + rect(metal1 13020 2420 13380 3180) + rect(metal1 13020 2420 13380 3180) + rect(metal1 15660 2420 16020 3180) + rect(metal1 15660 2420 16020 3180) + rect(metal1 18300 2420 18660 3180) + rect(metal1 18300 2420 18660 3180) + rect(metal1 20940 2420 21300 3180) + rect(metal1 20940 2420 21300 3180) + rect(metal1 23580 2420 23940 3180) + rect(metal1 23580 2420 23940 3180) + rect(metal2_lbl -1 2799 1 2801) + ) + net($I19 + 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) + ) + net($I8 + rect(diff_cont 21810 2890 22030 3110) + rect(diff_cont 21810 2490 22030 2710) + rect(diff_cont 21810 90 22030 310) + rect(diff_cont 21810 -310 22030 -90) + ) + net($I7 + rect(diff_cont 19170 2890 19390 3110) + rect(diff_cont 19170 2490 19390 2710) + rect(diff_cont 19170 90 19390 310) + rect(diff_cont 19170 -310 19390 -90) + ) + net($I6 + rect(diff_cont 16530 2890 16750 3110) + rect(diff_cont 16530 2490 16750 2710) + rect(diff_cont 16530 90 16750 310) + rect(diff_cont 16530 -310 16750 -90) + ) + net($I5 + rect(diff_cont 13890 2890 14110 3110) + rect(diff_cont 13890 2490 14110 2710) + rect(diff_cont 13890 90 14110 310) + rect(diff_cont 13890 -310 14110 -90) + ) + net($I4 + rect(diff_cont 11250 2890 11470 3110) + rect(diff_cont 11250 2490 11470 2710) + rect(diff_cont 11250 90 11470 310) + rect(diff_cont 11250 -310 11470 -90) + ) + net($I3 + rect(diff_cont 8610 2890 8830 3110) + rect(diff_cont 8610 2490 8830 2710) + rect(diff_cont 8610 90 8830 310) + rect(diff_cont 8610 -310 8830 -90) + ) + net($I2 + rect(diff_cont 5970 2890 6190 3110) + rect(diff_cont 5970 2490 6190 2710) + rect(diff_cont 5970 90 6190 310) + rect(diff_cont 5970 -310 6190 -90) + ) + net($I1 + rect(diff_cont 3330 2890 3550 3110) + rect(diff_cont 3330 2490 3550 2710) + rect(diff_cont 3330 90 3550 310) + rect(diff_cont 3330 -310 3550 -90) + ) + + # Subcircuits and their connections + subcircuit($1 location(23760 0) + pin(IN $I8) + pin($1 FB) + pin($3 VSS) + pin($4 VDD) + ) + subcircuit($2 location(0 0) + pin(IN FB) + pin(OUT $I19) + pin($3 VSS) + pin($4 VDD) + ) + subcircuit($3 location(2640 0) + pin(IN $I19) + pin(OUT $I1) + pin($3 VSS) + pin($4 VDD) + ) + subcircuit($4 location(5280 0) + pin(IN $I1) + pin(OUT $I2) + pin($3 VSS) + pin($4 VDD) + ) + subcircuit($5 location(7920 0) + pin(IN $I2) + pin(OUT $I3) + pin($3 VSS) + pin($4 VDD) + ) + subcircuit($6 location(10560 0) + pin(IN $I3) + pin(OUT $I4) + pin($3 VSS) + pin($4 VDD) + ) + subcircuit($7 location(13200 0) + pin(IN $I4) + pin(OUT $I5) + pin($3 VSS) + pin($4 VDD) + ) + subcircuit($8 location(15840 0) + pin(IN $I5) + pin(OUT $I6) + pin($3 VSS) + pin($4 VDD) + ) + subcircuit($9 location(18480 0) + pin(IN $I6) + pin(OUT $I7) + pin($3 VSS) + pin($4 VDD) + ) + subcircuit($10 location(21120 0) + pin(IN $I7) + pin(OUT $I8) + pin($3 VSS) + pin($4 VDD) + ) + +) + +# 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) + ) + +)