From 6648b53822932bbe4c1358db2c2f1f12641d4d71 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 20 Nov 2019 21:56:12 +0100 Subject: [PATCH] Fixed issue #419 (multiple top circuits after flatten of netlist) The problem is solved by always producing subcircuits for cell instances, even if there are no connections. The netlist comparer had to be adjusted too because subcircuits without pins were used for representing "unknown" subcircuit pairing. In addition, this patch should lead to a better matching of parallel subcircuit configurations where two different subcircuits are entirely parallel. --- src/db/db/dbLayoutToNetlist.cc | 6 +- src/db/db/dbLayoutToNetlist.h | 2 +- src/db/db/dbNetlistCompare.cc | 71 +++++-- src/db/db/dbNetlistExtractor.cc | 102 +++++++--- src/db/db/dbNetlistExtractor.h | 50 ++++- src/db/db/gsiDeclDbLayoutToNetlist.cc | 9 +- src/db/unit_tests/dbNetlistExtractorTests.cc | 179 +++++++++++++++++- .../lay_plugin/layNetTracerDialog.cc | 2 +- ...device_extract_l1_floating_subcircuits.gds | Bin 0 -> 4290 bytes 9 files changed, 361 insertions(+), 60 deletions(-) create mode 100644 testdata/algo/device_extract_l1_floating_subcircuits.gds diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index b30dfb26a..6645e828e 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -294,7 +294,7 @@ size_t LayoutToNetlist::global_net_id (const std::string &name) return m_conn.global_net_id (name); } -void LayoutToNetlist::extract_netlist (const std::string &joined_net_names) +void LayoutToNetlist::extract_netlist (const std::string &joined_net_names, bool include_floating_subcircuits) { if (m_netlist_extracted) { throw tl::Exception (tl::to_string (tr ("The netlist has already been extracted"))); @@ -302,7 +302,9 @@ void LayoutToNetlist::extract_netlist (const std::string &joined_net_names) ensure_netlist (); db::NetlistExtractor netex; - netex.extract_nets (dss (), m_layout_index, m_conn, *mp_netlist, m_net_clusters, joined_net_names); + netex.set_joined_net_names (joined_net_names); + netex.set_include_floating_subcircuits (include_floating_subcircuits); + netex.extract_nets (dss (), m_layout_index, m_conn, *mp_netlist, m_net_clusters); m_netlist_extracted = true; } diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h index 3b31ddff3..57cc2bdee 100644 --- a/src/db/db/dbLayoutToNetlist.h +++ b/src/db/db/dbLayoutToNetlist.h @@ -389,7 +389,7 @@ public: * @brief Runs the netlist extraction * See the class description for more details. */ - void extract_netlist (const std::string &joined_net_names = std::string ()); + void extract_netlist (const std::string &joined_net_names = std::string (), bool include_floating_subcircuits = false); /** * @brief Marks the netlist as extracted diff --git a/src/db/db/dbNetlistCompare.cc b/src/db/db/dbNetlistCompare.cc index 7ca7590b2..a95f6fba2 100644 --- a/src/db/db/dbNetlistCompare.cc +++ b/src/db/db/dbNetlistCompare.cc @@ -2624,18 +2624,15 @@ compute_device_key (const db::Device &device, const db::NetGraph &g, bool strict return k; } -static std::vector > -compute_subcircuit_key (const db::SubCircuit &subcircuit, const db::NetGraph &g, const std::map *circuit_map, const CircuitPinMapper *pin_map) +static bool +compute_subcircuit_key (const db::SubCircuit &subcircuit, const db::NetGraph &g, const std::map *circuit_map, const CircuitPinMapper *pin_map, std::vector > &k) { - std::vector > k; - const db::Circuit *cr = subcircuit.circuit_ref (); std::map::const_iterator icm = circuit_map->find (cr); if (icm == circuit_map->end ()) { - // this can happen if the other circuit does not exist - in this case the key is an invalid one which cannot - // be produced by a regular subcircuit. - return k; + // this can happen if the other circuit does not exist - report invalid mapping. + return false; } const CircuitMapper *cm = & icm->second; @@ -2660,7 +2657,7 @@ compute_subcircuit_key (const db::SubCircuit &subcircuit, const db::NetGraph &g, std::sort (k.begin (), k.end ()); - return k; + return true; } namespace { @@ -3349,7 +3346,8 @@ NetlistComparer::do_subcircuit_assignment (const db::Circuit *c1, const db::NetG continue; } - std::vector > k = compute_subcircuit_key (*sc, g1, &c12_circuit_and_pin_mapping, &circuit_pin_mapper); + std::vector > k; + bool valid = compute_subcircuit_key (*sc, g1, &c12_circuit_and_pin_mapping, &circuit_pin_mapper, k); bool mapped = true; for (std::vector >::iterator i = k.begin (); i != k.end () && mapped; ++i) { @@ -3363,7 +3361,7 @@ NetlistComparer::do_subcircuit_assignment (const db::Circuit *c1, const db::NetG mp_logger->subcircuit_mismatch (sc.operator-> (), 0); } good = false; - } else if (! k.empty ()) { + } else if (valid) { // TODO: report devices which cannot be distiguished topologically? subcircuit_map.insert (std::make_pair (k, std::make_pair (sc.operator-> (), sc_cat))); } @@ -3381,7 +3379,8 @@ NetlistComparer::do_subcircuit_assignment (const db::Circuit *c1, const db::NetG continue; } - std::vector > k = compute_subcircuit_key (*sc, g2, &c22_circuit_and_pin_mapping, &circuit_pin_mapper); + std::vector > k; + compute_subcircuit_key (*sc, g2, &c22_circuit_and_pin_mapping, &circuit_pin_mapper, k); bool mapped = true; for (std::vector >::iterator i = k.begin (); i != k.end (); ++i) { @@ -3407,18 +3406,50 @@ NetlistComparer::do_subcircuit_assignment (const db::Circuit *c1, const db::NetG db::SubCircuitCompare scc; - if (! scc.equals (scm->second, std::make_pair (sc.operator-> (), sc_cat))) { - if (mp_logger) { - mp_logger->subcircuit_mismatch (scm->second.first, sc.operator-> ()); - } - good = false; - } else { - if (mp_logger) { - mp_logger->match_subcircuits (scm->second.first, sc.operator-> ()); + std::multimap >, std::pair >::iterator scm_start = scm; + + bool found = false; + size_t nscm = 0; + while (! found && scm != subcircuit_map.end () && scm->first == k) { + ++nscm; + if (scc.equals (scm->second, std::make_pair (sc.operator-> (), sc_cat))) { + found = true; } } - subcircuit_map.erase (scm); + if (! found) { + + if (nscm == 1) { + + // unique match, but doesn't fit: report this one as paired, but mismatching: + if (mp_logger) { + mp_logger->subcircuit_mismatch (scm_start->second.first, sc.operator-> ()); + } + + // no longer look for this one + subcircuit_map.erase (scm_start); + + } else { + + // no unqiue match + if (mp_logger) { + mp_logger->subcircuit_mismatch (0, sc.operator-> ()); + } + + } + + good = false; + + } else { + + if (mp_logger) { + mp_logger->match_subcircuits (scm->second.first, sc.operator-> ()); + } + + // no longer look for this one + subcircuit_map.erase (scm); + + } } diff --git a/src/db/db/dbNetlistExtractor.cc b/src/db/db/dbNetlistExtractor.cc index 8231a1c0f..481dda8cb 100644 --- a/src/db/db/dbNetlistExtractor.cc +++ b/src/db/db/dbNetlistExtractor.cc @@ -29,11 +29,21 @@ namespace db { NetlistExtractor::NetlistExtractor () - : mp_clusters (0), mp_layout (0), mp_cell (0) + : mp_clusters (0), mp_layout (0), mp_cell (0), m_include_floating_subcircuits (false) { // .. nothing yet .. } +void NetlistExtractor::set_joined_net_names (const std::string &jnn) +{ + m_joined_net_names = jnn; +} + +void NetlistExtractor::set_include_floating_subcircuits (bool f) +{ + m_include_floating_subcircuits = f; +} + static void build_net_name_equivalence (const db::Layout *layout, db::property_names_id_type net_name_id, const std::string &joined_net_names, tl::equivalence_clusters &eq) { @@ -62,7 +72,7 @@ build_net_name_equivalence (const db::Layout *layout, db::property_names_id_type } void -NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layout_index, const db::Connectivity &conn, db::Netlist &nl, hier_clusters_type &clusters, const std::string &joined_net_names) +NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layout_index, const db::Connectivity &conn, db::Netlist &nl, hier_clusters_type &clusters) { mp_clusters = &clusters; mp_layout = &dss.const_layout (layout_index); @@ -81,8 +91,8 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layo // the big part: actually extract the nets tl::equivalence_clusters net_name_equivalence; - if (m_text_annot_name_id.first && ! joined_net_names.empty ()) { - build_net_name_equivalence (mp_layout, m_text_annot_name_id.second, joined_net_names, net_name_equivalence); + if (m_text_annot_name_id.first && ! m_joined_net_names.empty ()) { + build_net_name_equivalence (mp_layout, m_text_annot_name_id.second, m_joined_net_names, net_name_equivalence); } mp_clusters->build (*mp_layout, *mp_cell, db::ShapeIterator::Polygons, conn, &net_name_equivalence); @@ -98,9 +108,25 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layo 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) { + const db::Cell &cell = mp_layout->cell (*cid); + const connected_clusters_type &clusters = mp_clusters->clusters_per_cell (*cid); if (clusters.empty ()) { - continue; + + bool any_good = false; + + // in case of "include floating subcircuits" check whether we have a child cell which has a circuit attached in this case + if (include_floating_subcircuits ()) { + for (db::Cell::child_cell_iterator cc = cell.begin_child_cells (); ! any_good && ! cc.at_end (); ++cc) { + any_good = (circuits.find (*cc) != circuits.end ()); + } + } + + if (! any_good) { + // skip this cell + continue; + } + } db::DeviceAbstract *dm = nl.device_abstract_by_cell_index (*cid); @@ -128,6 +154,16 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layo std::map, db::SubCircuit *> subcircuits; + if (include_floating_subcircuits ()) { + + // Make sure we create one subcircuit for each instance of cells which do have circuits + // associated. + for (db::Cell::const_iterator inst = cell.begin (); ! inst.at_end (); ++inst) { + make_subcircuit (circuit, inst->cell_index (), inst->complex_trans (), subcircuits, circuits); + } + + } + for (connected_clusters_type::all_iterator c = clusters.begin_all (); ! c.at_end (); ++c) { const db::local_cluster &lc = clusters.cluster_by_id (*c); @@ -315,6 +351,39 @@ void NetlistExtractor::connect_devices (db::Circuit *circuit, } } +db::SubCircuit * NetlistExtractor::make_subcircuit (db::Circuit *circuit, + db::cell_index_type inst_cell_index, + const db::ICplxTrans &inst_trans, + std::map, db::SubCircuit *> &subcircuits, + const std::map &circuits) +{ + db::SubCircuit *subcircuit = 0; + + std::pair subcircuit_key (inst_cell_index, inst_trans); + + std::map, db::SubCircuit *>::const_iterator j = subcircuits.find (subcircuit_key); + if (j == subcircuits.end ()) { + + // make subcircuit if required + + std::map::const_iterator k = circuits.find (inst_cell_index); + if (k == circuits.end ()) { + return 0; + } + + subcircuit = new db::SubCircuit (k->second); + db::CplxTrans dbu_trans (mp_layout->dbu ()); + subcircuit->set_trans (dbu_trans * inst_trans * dbu_trans.inverted ()); + circuit->add_subcircuit (subcircuit); + subcircuits.insert (std::make_pair (subcircuit_key, subcircuit)); + + } else { + subcircuit = j->second; + } + + return subcircuit; +} + void NetlistExtractor::make_and_connect_subcircuits (db::Circuit *circuit, const connected_clusters_type &clusters, size_t cid, @@ -335,27 +404,8 @@ void NetlistExtractor::make_and_connect_subcircuits (db::Circuit *circuit, continue; } - db::SubCircuit *subcircuit = 0; - - std::pair subcircuit_key (inst_cell_index, inst_trans); - - std::map, db::SubCircuit *>::const_iterator j = subcircuits.find (subcircuit_key); - if (j == subcircuits.end ()) { - - // make subcircuit if required - - std::map::const_iterator k = circuits.find (inst_cell_index); - tl_assert (k != circuits.end ()); // because we walk bottom-up - - subcircuit = new db::SubCircuit (k->second); - db::CplxTrans dbu_trans (mp_layout->dbu ()); - subcircuit->set_trans (dbu_trans * inst_trans * dbu_trans.inverted ()); - circuit->add_subcircuit (subcircuit); - subcircuits.insert (std::make_pair (subcircuit_key, subcircuit)); - - } else { - subcircuit = j->second; - } + db::SubCircuit *subcircuit = make_subcircuit (circuit, inst_cell_index, inst_trans, subcircuits, circuits); + tl_assert (subcircuit != 0); // create the pin connection to the subcircuit std::map >::const_iterator icc2p = pins_per_cluster.find (inst_cell_index); diff --git a/src/db/db/dbNetlistExtractor.h b/src/db/db/dbNetlistExtractor.h index d1504f1d3..8cd0a64dc 100644 --- a/src/db/db/dbNetlistExtractor.h +++ b/src/db/db/dbNetlistExtractor.h @@ -80,11 +80,45 @@ public: */ NetlistExtractor (); + /** + * @brief Sets a flag indicating whether floating circuits shall be included as subcircuits + * If this attribute is set to true, disconnected subcircuits (such that do not have a pin) + * are included per instance of a cell. Such subcircuits do not have a connection to their + * parent circuit but reflect the hierarchy they are present it. This is useful when the + * netlist is supposed to be flattened later, because then each subcircuit will render floating + * nets in the parent circuit. With this flag set to false, floating circuits will always appear + * as additional top cells. + */ + void set_include_floating_subcircuits (bool f); + + /** + * @brief Gets a flag indicating whether floating circuits shall be included as subcircuits + */ + bool include_floating_subcircuits () const + { + return m_include_floating_subcircuits; + } + + /** + * @brief Sets the joined net names attribute + * This is a glob expression rendering net names where partial nets with the + * same name are joined even without explicit connection. + */ + void set_joined_net_names (const std::string &jnn); + + /** + * @brief Gets the joined net names expression + */ + const std::string &joined_net_names () const + { + return m_joined_net_names; + } + /** * @brief Extract the nets * See the class description for more details. */ - void extract_nets (const db::DeepShapeStore &dss, unsigned int layout_index, const db::Connectivity &conn, db::Netlist &nl, hier_clusters_type &clusters, const std::string &joined_net_names = std::string ()); + void extract_nets (const db::DeepShapeStore &dss, unsigned int layout_index, const db::Connectivity &conn, db::Netlist &nl, hier_clusters_type &clusters); private: hier_clusters_type *mp_clusters; @@ -93,6 +127,8 @@ private: std::pair m_text_annot_name_id; std::pair m_device_annot_name_id; std::pair m_terminal_annot_name_id; + std::string m_joined_net_names; + bool m_include_floating_subcircuits; bool instance_is_device (db::properties_id_type prop_id) const; db::Device *device_from_instance (db::properties_id_type prop_id, db::Circuit *circuit) const; @@ -106,6 +142,18 @@ private: */ size_t make_pin (db::Circuit *circuit, db::Net *net); + /** + * @brief Makes a subcircuit for the given instance (by cell index and transformation) + * This method maintains a subcircuit cache in "subcircuits" and will pull the subcircuit from there + * if possible. + * It returns the new or old subcircuit. + */ + db::SubCircuit *make_subcircuit (Circuit *circuit, + db::cell_index_type inst_cell_index, + const db::ICplxTrans &inst_trans, + std::map, db::SubCircuit *> &subcircuits, + const std::map &circuits); + /** * @brief Turns the connections of a cluster into subcircuit instances * diff --git a/src/db/db/gsiDeclDbLayoutToNetlist.cc b/src/db/db/gsiDeclDbLayoutToNetlist.cc index c8256b0c7..5f53b5898 100644 --- a/src/db/db/gsiDeclDbLayoutToNetlist.cc +++ b/src/db/db/gsiDeclDbLayoutToNetlist.cc @@ -329,7 +329,7 @@ Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist", gsi::method ("global_net_name", &db::LayoutToNetlist::global_net_name, gsi::arg ("global_net_id"), "@brief Gets the global net name for the given global net ID." ) + - gsi::method ("extract_netlist", &db::LayoutToNetlist::extract_netlist, gsi::arg ("join_net_names", std::string ()), + gsi::method ("extract_netlist", &db::LayoutToNetlist::extract_netlist, gsi::arg ("join_net_names", std::string ()), gsi::arg ("include_floating_subcircuits", false), "@brief Runs the netlist extraction\n" "'join_net_names' is a glob expression for labels. Nets on top level carrying the same label which matches this glob " "expression will be connected implicitly even if there is no physical connection. This feature is useful to simulate a connection " @@ -346,7 +346,14 @@ Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist", "\n" "Label matching is case sensitive.\n" "\n" + "With 'include_floating_subcircuits' set to true, subcircuits with no connection to their parent " + "circuit are still included in the circuit as floating subcircuits. Specifically on flattening this " + "means that these subcircuits are property propagated to their parent instead of appearing as " + "additional top circuits.\n" + "\n" "See the class description for more details.\n" + "\n" + "The 'include_floating_subcircuits' argument has been introduced in version 0.26.2." ) + gsi::method_ext ("internal_layout", &l2n_internal_layout, "@brief Gets the internal layout\n" diff --git a/src/db/unit_tests/dbNetlistExtractorTests.cc b/src/db/unit_tests/dbNetlistExtractorTests.cc index e04637320..6fd7c205f 100644 --- a/src/db/unit_tests/dbNetlistExtractorTests.cc +++ b/src/db/unit_tests/dbNetlistExtractorTests.cc @@ -741,16 +741,19 @@ TEST(3_DeviceAndNetExtractionWithImplicitConnections) // extract the nets db::Netlist nl2 = nl; - net_ex.extract_nets (dss, 0, conn, nl2, cl, "{VDDZ,VSSZ,NEXT,FB}"); + net_ex.set_joined_net_names ("{VDDZ,VSSZ,NEXT,FB}"); + net_ex.extract_nets (dss, 0, conn, nl2, cl); EXPECT_EQ (all_net_names_unique (nl2), true); nl2 = nl; - net_ex.extract_nets (dss, 0, conn, nl2, cl, "{VDDZ,VSSZ,NEXT}"); + net_ex.set_joined_net_names ("{VDDZ,VSSZ,NEXT}"); + net_ex.extract_nets (dss, 0, conn, nl2, cl); EXPECT_EQ (all_net_names_unique (nl2), false); - net_ex.extract_nets (dss, 0, conn, nl, cl, "*"); + net_ex.set_joined_net_names ("*"); + net_ex.extract_nets (dss, 0, conn, nl, cl); EXPECT_EQ (all_net_names_unique (nl), true); @@ -1012,7 +1015,8 @@ TEST(4_ResAndCapExtraction) // extract the nets - net_ex.extract_nets (dss, 0, conn, nl, cl, "*"); + net_ex.set_joined_net_names ("*"); + net_ex.extract_nets (dss, 0, conn, nl, cl); // Flatten device circuits @@ -1285,7 +1289,8 @@ TEST(5_ResAndCapWithBulkExtraction) // extract the nets - net_ex.extract_nets (dss, 0, conn, nl, cl, "*"); + net_ex.set_joined_net_names ("*"); + net_ex.extract_nets (dss, 0, conn, nl, cl); // Flatten device circuits @@ -1526,7 +1531,8 @@ TEST(6_BJT3TransistorExtraction) // extract the nets - net_ex.extract_nets (dss, 0, conn, nl, cl, "*"); + net_ex.set_joined_net_names ("*"); + net_ex.extract_nets (dss, 0, conn, nl, cl); // Flatten device circuits @@ -1691,7 +1697,8 @@ TEST(7_DiodeExtraction) // extract the nets - net_ex.extract_nets (dss, 0, conn, nl, cl, "*"); + net_ex.set_joined_net_names ("*"); + net_ex.extract_nets (dss, 0, conn, nl, cl); // cleanup + completion nl.combine_devices (); @@ -1823,7 +1830,8 @@ TEST(8_DiodeExtractionScaled) // extract the nets - net_ex.extract_nets (dss, 0, conn, nl, cl, "*"); + net_ex.set_joined_net_names ("*"); + net_ex.extract_nets (dss, 0, conn, nl, cl); // cleanup + completion nl.combine_devices (); @@ -2303,3 +2311,158 @@ TEST(10_DeviceExtractionWithBreakoutCells) db::compare_layouts (_this, ly, au); } + +TEST(11_FloatingSubcircuitExtraction) +{ + db::Layout ly; + db::LayerMap lmap; + + unsigned int nwell = define_layer (ly, lmap, 1); + unsigned int active = define_layer (ly, lmap, 2); + unsigned int poly = define_layer (ly, lmap, 3); + unsigned int poly_lbl = define_layer (ly, lmap, 3, 1); + unsigned int diff_cont = define_layer (ly, lmap, 4); + unsigned int poly_cont = define_layer (ly, lmap, 5); + unsigned int metal1 = define_layer (ly, lmap, 6); + unsigned int metal1_lbl = define_layer (ly, lmap, 6, 1); + unsigned int via1 = define_layer (ly, lmap, 7); + unsigned int metal2 = define_layer (ly, lmap, 8); + unsigned int metal2_lbl = define_layer (ly, lmap, 8, 1); + + { + db::LoadLayoutOptions options; + options.get_options ().layer_map = lmap; + options.get_options ().create_other_layers = false; + + std::string fn (tl::testsrc ()); + fn = tl::combine_path (fn, "testdata"); + fn = tl::combine_path (fn, "algo"); + fn = tl::combine_path (fn, "device_extract_l1_floating_subcircuits.gds"); + + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly, options); + } + + db::Cell &tc = ly.cell (*ly.begin_top_down ()); + + db::DeepShapeStore dss; + dss.set_text_enlargement (1); + dss.set_text_property_name (tl::Variant ("LABEL")); + + // original layers + db::Region rnwell (db::RecursiveShapeIterator (ly, tc, nwell), dss); + db::Region ractive (db::RecursiveShapeIterator (ly, tc, active), dss); + db::Region rpoly (db::RecursiveShapeIterator (ly, tc, poly), dss); + db::Region rpoly_lbl (db::RecursiveShapeIterator (ly, tc, poly_lbl), dss); + db::Region rdiff_cont (db::RecursiveShapeIterator (ly, tc, diff_cont), dss); + db::Region rpoly_cont (db::RecursiveShapeIterator (ly, tc, poly_cont), dss); + db::Region rmetal1 (db::RecursiveShapeIterator (ly, tc, metal1), dss); + db::Region rmetal1_lbl (db::RecursiveShapeIterator (ly, tc, metal1_lbl), dss); + db::Region rvia1 (db::RecursiveShapeIterator (ly, tc, via1), dss); + db::Region rmetal2 (db::RecursiveShapeIterator (ly, tc, metal2), dss); + db::Region rmetal2_lbl (db::RecursiveShapeIterator (ly, tc, metal2_lbl), dss); + + // derived regions + + db::Region rpactive = ractive & rnwell; + db::Region rpgate = rpactive & rpoly; + db::Region rpsd = rpactive - rpgate; + + db::Region rnactive = ractive - rnwell; + db::Region rngate = rnactive & rpoly; + db::Region rnsd = rnactive - rngate; + + // perform the extraction + + db::Netlist nl; + db::hier_clusters cl; + + db::NetlistDeviceExtractorMOS3Transistor pmos_ex ("PMOS"); + db::NetlistDeviceExtractorMOS3Transistor nmos_ex ("NMOS"); + + db::NetlistDeviceExtractor::input_layers dl; + + dl["SD"] = &rpsd; + dl["G"] = &rpgate; + dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes + pmos_ex.extract (dss, 0, dl, nl, cl); + + dl["SD"] = &rnsd; + dl["G"] = &rngate; + dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes + nmos_ex.extract (dss, 0, dl, nl, cl); + + // perform the net extraction + + db::Connectivity conn; + // Intra-layer + conn.connect (rpsd); + conn.connect (rnsd); + conn.connect (rpoly); + conn.connect (rdiff_cont); + conn.connect (rpoly_cont); + conn.connect (rmetal1); + conn.connect (rvia1); + conn.connect (rmetal2); + // Inter-layer + conn.connect (rpsd, rdiff_cont); + conn.connect (rnsd, rdiff_cont); + conn.connect (rpoly, rpoly_cont); + conn.connect (rpoly_cont, rmetal1); + conn.connect (rdiff_cont, rmetal1); + conn.connect (rmetal1, rvia1); + conn.connect (rvia1, rmetal2); + conn.connect (rpoly, rpoly_lbl); // attaches labels + conn.connect (rmetal1, rmetal1_lbl); // attaches labels + conn.connect (rmetal2, rmetal2_lbl); // attaches labels + + // extract the nets + + db::NetlistExtractor net_ex; + net_ex.set_include_floating_subcircuits (true); + net_ex.extract_nets (dss, 0, conn, nl, cl); + + // compare netlist as string + CHECKPOINT (); + db::compare_netlist (_this, nl, + "circuit RINGO ();\n" + " subcircuit INV2 $1 (IN=FB,$2=$I29,OUT=$I1,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $2 (IN=$I1,$2=$I30,OUT=$I2,$4=VSS,$5=VDD);\n" + " subcircuit INV2X $3 ($1=VDD,$2=VSS,$3=$I25,$4=$I11);\n" + " subcircuit TRANSISO $4 ();\n" // effect of "include floating subcircuits"! + " subcircuit INV2 $5 (IN=$I9,$2=$I31,OUT=$I3,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $6 (IN=$I3,$2=$I32,OUT=$I25,$4=VSS,$5=VDD);\n" + " subcircuit TRANSISOB $7 ();\n" // effect of "include floating subcircuits"! + " subcircuit INV2 $7 (IN=$I11,$2=$I33,OUT=$I5,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $8 (IN=$I5,$2=FB,OUT=OSC,$4=VSS,$5=VDD);\n" + " subcircuit INV2X $9 ($1=VDD,$2=VSS,$3=$I2,$4=$I9);\n" + "end;\n" + "circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);\n" + " device PMOS $1 (S=$2,G=IN,D=$5) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n" + " device PMOS $2 (S=$5,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n" + " device NMOS $3 (S=$2,G=IN,D=$4) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n" + " device NMOS $4 (S=$4,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n" + " subcircuit TRANS $1 ($1=$2,$2=$4,$3=IN);\n" + " subcircuit TRANS $2 ($1=$2,$2=$5,$3=IN);\n" + " subcircuit TRANS $3 ($1=$4,$2=OUT,$3=$2);\n" + " subcircuit TRANS $4 ($1=$5,$2=OUT,$3=$2);\n" + "end;\n" + "circuit TRANS ($1=$1,$2=$2,$3=$3);\n" + "end;\n" + "circuit INV2X ($1=$I4,$2=$I3,$3=$I2,$4=$I1);\n" + " subcircuit INV2 $1 (IN=$I2,$2=$I6,OUT=$I5,$4=$I3,$5=$I4);\n" + " subcircuit INV2 $2 (IN=$I5,$2=$I7,OUT=$I1,$4=$I3,$5=$I4);\n" + " subcircuit TRANSISO $3 ();\n" // effect of "include floating subcircuits"! + " subcircuit TRANSISO $4 ();\n" // effect of "include floating subcircuits"! + " subcircuit TRANSISOB $5 ();\n" // effect of "include floating subcircuits"! + "end;\n" + "circuit TRANSISO ();\n" + " device NMOS $1 (S=$1,G=$2,D=$1) (L=0.25,W=0.95,AS=0.49875,AD=0.49875,PS=2.95,PD=2.95);\n" + "end;\n" + "circuit TRANSISOB ();\n" + " device NMOS $1 (S=$1,G=$2,D=$1) (L=0.25,W=0.95,AS=0.49875,AD=0.49875,PS=2.95,PD=2.95);\n" + "end;\n" + ); +} + diff --git a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.cc b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.cc index 7af1299ea..44ed42267 100644 --- a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.cc +++ b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.cc @@ -1669,7 +1669,7 @@ NetTracerDialog::trace_all_nets (db::LayoutToNetlist *l2ndb, const lay::CellView tracer_data.configure_l2n (*l2ndb); - l2ndb->extract_netlist (); + l2ndb->extract_netlist (std::string (), flat /*include floating subcircuits for netlist to flatten*/); if (flat) { l2ndb->netlist ()->flatten (); diff --git a/testdata/algo/device_extract_l1_floating_subcircuits.gds b/testdata/algo/device_extract_l1_floating_subcircuits.gds new file mode 100644 index 0000000000000000000000000000000000000000..024b05e2015bba40a2bd095603337caa45f997af GIT binary patch literal 4290 zcmeHKO=wg}5UzPM({E-niBY4Anu9J13Q@uMgJh9pHvWW2BAGF02qZ@@f}n_qilBl& z2!eZZJ&5eO2XC?qf}TV~a@wP?%OdP~A)uEGI?u0ObZ5`9Zz_1^@JNNIC!60lbYsuxtKa7L4nN)g;OD6t_2!d# zC1Yw6Lt|B;wK;{1jO{~W%+ z;1Tej2-V)0OXFiDQ_M%)-OP_r?KG9d$Jp<|nG*~i0UI1&Q0>X_naA-3GrO6GuSK=D z#5eK%e|(PkS8;yN!MlLi8x_^g=&V1+N9?~tKahDi|6xV7NBpAXFKgqQ4V=ZovMm1A zsi&Kfg5bkjMxyL`iRx2oeRSFS7^#j|q8u;PNb`;$AKy@o*gGDpF|J9jA+1f6hOITJ zJ@reqe3cq2M>V#jLN-G&6J1AEoDy`6tSLP1aI2Foa*umO+OY>6u zj@PWsTqeQ{$j+UF8Cu5ZJoXOh9gOL8<^*@$P@9QfLvCj=vqc|;0nH}G;+dqb0gdm& zzNQ(8if7P$eo|CBV+#K*V(pY(k-INlM^WwBoep2Sj=UP)K{X8GzC#1z?*E^n+8LAh zIMJ1%AILn!?^INKI-eB`>kE}k*R81bwDm7cqm|ZzfYIj;jv7%^yQw+rFT}fk{W>`N zf}nmKdwD^WKc}d6#xy?iwN3ctC&E`$dvTk?&$#iqPK4j}M)-cb4nJYEWe*%iS2SY<=OLVR`Jry*^yUZc zPl_TTv-+CLf-|KF(ntdA?WRYB`7 zML`+=kAf~7!ni@q1LTvNf`Tfl-3-d=Z2Xu46U}U9z992vp9-H*?Jayqffnv!+%3ch z`q!Xfw|O)*Ao- literal 0 HcmV?d00001