diff --git a/src/db/db/dbNetlist.cc b/src/db/db/dbNetlist.cc index 6b536c817..429ea8b7d 100644 --- a/src/db/db/dbNetlist.cc +++ b/src/db/db/dbNetlist.cc @@ -396,6 +396,22 @@ void Netlist::flatten_circuit (Circuit *circuit) delete circuit; } +void Netlist::flatten () +{ + std::set top_circuits; + size_t ntop = top_circuit_count (); + for (db::Netlist::top_down_circuit_iterator tc = begin_top_down (); tc != end_top_down () && ntop > 0; ++tc) { + top_circuits.insert (tc.operator-> ()); + --ntop; + } + + for (db::Netlist::bottom_up_circuit_iterator c = begin_bottom_up (); c != end_bottom_up(); ++c) { + if (top_circuits.find (c.operator-> ()) == top_circuits.end ()) { + flatten_circuit (c.operator-> ()); + } + } +} + DeviceClass *Netlist::device_class_by_name (const std::string &name) { for (device_class_iterator d = begin_device_classes (); d != end_device_classes (); ++d) { diff --git a/src/db/db/dbNetlist.h b/src/db/db/dbNetlist.h index da26bd399..760fa381f 100644 --- a/src/db/db/dbNetlist.h +++ b/src/db/db/dbNetlist.h @@ -174,6 +174,11 @@ public: */ void flatten_circuit (Circuit *circuit); + /** + * @brief Flattens the netlist + */ + void flatten (); + /** * @brief Begin iterator for the circuits of the netlist (non-const version) */ diff --git a/src/db/db/gsiDeclDbNetlist.cc b/src/db/db/gsiDeclDbNetlist.cc index f229dafb1..9e59ea3c2 100644 --- a/src/db/db/gsiDeclDbNetlist.cc +++ b/src/db/db/gsiDeclDbNetlist.cc @@ -1388,6 +1388,10 @@ Class decl_dbNetlist ("db", "Netlist", "A circuit with references (see \\has_refs?) should not be removed as the " "subcircuits calling it would afterwards point to nothing." ) + + gsi::method ("flatten", &db::Netlist::flatten, + "@brief Flattens all circuits of the netlist\n" + "After calling this method, only the top circuits will remain." + ) + gsi::method ("flatten_circuit", &db::Netlist::flatten_circuit, gsi::arg ("circuit"), "@brief Flattens a subcircuit\n" "This method will substitute all instances (subcircuits) of the given circuit by it's " diff --git a/src/db/unit_tests/dbNetlistTests.cc b/src/db/unit_tests/dbNetlistTests.cc index a4db90bb7..9de025763 100644 --- a/src/db/unit_tests/dbNetlistTests.cc +++ b/src/db/unit_tests/dbNetlistTests.cc @@ -1188,6 +1188,20 @@ TEST(20_FlattenSubCircuit) " device NMOS $4 (S=$4,G=$2,D=OUT) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" "end;\n" ); + + db::Netlist nl3; + + nl3 = nl; + nl3.flatten (); + + EXPECT_EQ (nl3.to_string (), + "circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);\n" + " device PMOS $1 (S=$5,G=IN,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" + " device PMOS $2 (S=$5,G=$2,D=OUT) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" + " device NMOS $3 (S=$4,G=IN,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" + " device NMOS $4 (S=$4,G=$2,D=OUT) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" + "end;\n" + ); } TEST(21_FlattenSubCircuit2) diff --git a/src/lay/lay/doc/manual/lvs_compare.xml b/src/lay/lay/doc/manual/lvs_compare.xml index 72e60825e..01dd882fc 100644 --- a/src/lay/lay/doc/manual/lvs_compare.xml +++ b/src/lay/lay/doc/manual/lvs_compare.xml @@ -46,7 +46,7 @@
same_nets("LOGIC", "VDD", "VDD:P")

- In this example it is assumed that the power net is labelled "VDD" in the + In this example it is assumed that the power net is labeled "VDD" in the layout and called "VDD:P" in the schematic. Don't leave this statement in the script for final verification as it may mask real errors.

@@ -160,7 +160,8 @@ same_device_classes("NMOS_IN_LAYOUT", "NMOS_IN_SCHEMATIC")

- In general, it's a good idea to include "align" before the "compare" step. + In general, it's a good idea to include "align" before "netlist.simplify" or + similar netlist manipulation and the "compare" step.

diff --git a/src/lay/lay/doc/manual/lvs_connect.xml b/src/lay/lay/doc/manual/lvs_connect.xml index d05b817d7..e47efff0e 100644 --- a/src/lay/lay/doc/manual/lvs_connect.xml +++ b/src/lay/lay/doc/manual/lvs_connect.xml @@ -70,7 +70,7 @@ connect(metal2, metal2_labels)

If labels are connected to metal layers, their text strings will be used to assign - net names to the resulting nets. Ideally, one net is labelled with a single text + net names to the resulting nets. Ideally, one net is labeled with a single text or with texts with the same text string. In this case, the net name will be non-ambiguous. If multiple labels with different strings are present on a net, the net name will be made from a combination of these names. diff --git a/src/lay/lay/doc/manual/lvs_intro.xml b/src/lay/lay/doc/manual/lvs_intro.xml index d3278dd8e..ebd4cd94e 100644 --- a/src/lay/lay/doc/manual/lvs_intro.xml +++ b/src/lay/lay/doc/manual/lvs_intro.xml @@ -156,6 +156,9 @@ connect_global(nwell, "NWELL") schematic("inv.cir") +align # flattens unpaired circuits +netlist.simplify # removes floating nets, combines devices + compare

@@ -336,11 +339,35 @@ connect_global(nwell, "NWELL")

We have now provided all the essential inputs for the netlist formation. - We only have to specify the reference netlist: + We now have to specify the reference netlist:

schematic("inv.cir")
+

+ Two optional, but recommended steps are hierarchy alignment and extracted + netlist simplification: +

+ +
align              # flattens unpaired circuits 
+netlist.simplify   # removes floating nets, combines devices
+  
+ +

+ "align" will remove circuits which are not present in the other netlist by + integrating their content into the parent cell. This will remove auxiliary cells + which are usually present in a layout but don't map to a schematic cell (e.g. + device PCells). "netlist.simplify" reduces the netlist by floating nets, + performs device combination (e.g. fingered transistors). This method will + also create pins from labeled nets in the top level circuit. +

+ +

+ The order should be "align", then "netlist.simplify". Both have to happen before + "compare" to be effective. "align" is described in , + "netlist.simplify" in . +

+

Finally after having set this up, we can trigger the compare step:

@@ -498,6 +525,9 @@ connect_global(ptie, "SUBSTRATE") schematic("inv2.cir") +align +netlist.simplify + compare

diff --git a/src/lay/lay/doc/manual/lvs_tweaks.xml b/src/lay/lay/doc/manual/lvs_tweaks.xml index 997104258..f0300a18d 100644 --- a/src/lay/lay/doc/manual/lvs_tweaks.xml +++ b/src/lay/lay/doc/manual/lvs_tweaks.xml @@ -41,7 +41,7 @@

KLayout offers a function to create top-level pins using - a simple heuristics: for every named (i.e. labelled) net in the top level + a simple heuristics: for every named (i.e. labeled) net in the top level circuit a pin will be created ():

@@ -199,9 +199,16 @@ netlist.purge_nets

is a wrapper for "make_top_level_pins", - "combine_devices" and "purge" in the recommended order: + "purge", "combine_devices" and "purge_nets" in this recommended order:

netlist.simplify
+

+ As a technical detail, "make_top_level_pins" is included in this sequence as with + pins, nets are not considered floating. So "purge_nets" will maintain pins for + labeled nets even if these nets are not connected to devices. This allows adding + optional pins while maintaining the top level circuit's interface. +

+ diff --git a/src/lay/lay/doc/manual/net_tracing.xml b/src/lay/lay/doc/manual/net_tracing.xml index 6c8b3a416..cdb8a1271 100644 --- a/src/lay/lay/doc/manual/net_tracing.xml +++ b/src/lay/lay/doc/manual/net_tracing.xml @@ -101,7 +101,7 @@
  • Export all or selected nets to layout, save the netlist (with shapes) to a file, load it back from a file and manage the netlist database. Use the "File" menu button in the right upper corner.
  • -
  • Search for net names (if labelled) and circuits using the search edit box. +
  • Search for net names (if labeled) and circuits using the search edit box.
  • Navigate through the history using the "back" and "forward" buttons at the top left.
  • diff --git a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.cc b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.cc index c3303712a..7af1299ea 100644 --- a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.cc +++ b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.cc @@ -559,13 +559,15 @@ NetTracerDialog::menu_activated (const std::string &symbol) layer_stack_clicked (); - } else if (symbol == "lay::trace_all_nets") { + } else if (symbol == "lay::trace_all_nets" || symbol == "lay::trace_all_nets_flat") { + + bool flat = symbol == "lay::trace_all_nets_flat"; const lay::CellView &cv = view ()->cellview (view ()->active_cellview_index ()); if (cv.is_valid ()) { db::RecursiveShapeIterator si (cv->layout (), *cv.cell (), std::vector ()); std::auto_ptr l2ndb (new db::LayoutToNetlist (si)); - trace_all_nets (l2ndb.get (), cv); + trace_all_nets (l2ndb.get (), cv, flat); unsigned int l2ndb_index = view ()->add_l2ndb (l2ndb.release ()); view ()->open_l2ndb_browser (l2ndb_index, view ()->index_of_cellview (&cv)); } @@ -1658,7 +1660,7 @@ NetTracerDialog::clear_markers () } void -NetTracerDialog::trace_all_nets (db::LayoutToNetlist *l2ndb, const lay::CellView &cv) +NetTracerDialog::trace_all_nets (db::LayoutToNetlist *l2ndb, const lay::CellView &cv, bool flat) { db::NetTracerData tracer_data; if (! get_net_tracer_setup (cv, tracer_data)) { @@ -1668,6 +1670,10 @@ NetTracerDialog::trace_all_nets (db::LayoutToNetlist *l2ndb, const lay::CellView tracer_data.configure_l2n (*l2ndb); l2ndb->extract_netlist (); + + if (flat) { + l2ndb->netlist ()->flatten (); + } } } diff --git a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.h b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.h index 99479fe87..952ae1bba 100644 --- a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.h +++ b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.h @@ -118,7 +118,7 @@ private: void release_mouse (); db::NetTracerNet *do_trace (const db::DBox &start_search_box, const db::DBox &stop_search_box, bool trace_path); bool get_net_tracer_setup (const lay::CellView &cv, db::NetTracerData &data); - void trace_all_nets (db::LayoutToNetlist *l2ndb, const lay::CellView &cv); + void trace_all_nets (db::LayoutToNetlist *l2ndb, const lay::CellView &cv, bool flat); }; } diff --git a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerPlugin.cc b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerPlugin.cc index 523fce279..f08e93fe0 100644 --- a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerPlugin.cc +++ b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerPlugin.cc @@ -69,7 +69,9 @@ public: lay::PluginDeclaration::get_menu_entries (menu_entries); menu_entries.push_back (lay::MenuEntry ("net_trace_group", "tools_menu.end")); menu_entries.push_back (lay::MenuEntry ("lay::net_trace", "net_trace", "tools_menu.end", tl::to_string (QObject::tr ("Trace Net")))); - menu_entries.push_back (lay::MenuEntry ("lay::trace_all_nets", "trace_all_nets", "tools_menu.end", tl::to_string (QObject::tr ("Trace All Nets")))); + menu_entries.push_back (lay::MenuEntry ("", "trace_all_nets_menu", "tools_menu.end", tl::to_string (QObject::tr ("Trace All Nets")), true)); + menu_entries.push_back (lay::MenuEntry ("lay::trace_all_nets", "trace_all_nets", "tools_menu.trace_all_nets_menu.end", tl::to_string (QObject::tr ("Hierarchical")))); + menu_entries.push_back (lay::MenuEntry ("lay::trace_all_nets_flat", "trace_all_nets_flat", "tools_menu.trace_all_nets_menu.end", tl::to_string (QObject::tr ("Flat")))); menu_entries.push_back (lay::MenuEntry ("lay::edit_layer_stack", "edit_layer_stack", "tools_menu.end", tl::to_string (QObject::tr ("Edit Layer Stack")))); }