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 000000000..024b05e20 Binary files /dev/null and b/testdata/algo/device_extract_l1_floating_subcircuits.gds differ