diff --git a/src/db/db/dbDeepShapeStore.cc b/src/db/db/dbDeepShapeStore.cc index c398e6a55..399e366c0 100644 --- a/src/db/db/dbDeepShapeStore.cc +++ b/src/db/db/dbDeepShapeStore.cc @@ -319,10 +319,11 @@ struct DeepShapeStore::LayoutHolder { auto l = net_builders.find (l2n); if (l == net_builders.end ()) { - // @@@ what happens if layout is the same than used inside l2n (l2n has weak reference to same DSS)?? l = net_builders.insert (std::make_pair (l2n, std::make_pair (L2NStatusChangedListener (this, l2n), db::NetBuilder (&layout, l2n->cell_mapping_into (layout, top, false), l2n)))).first; + return l->second.second; + } else { + return l->second.second; } - return l->second.second; } void remove_l2n (db::LayoutToNetlist *l2n) @@ -343,7 +344,7 @@ struct DeepShapeStore::LayoutHolder // ---------------------------------------------------------------------------------- DeepShapeStoreState::DeepShapeStoreState () - : m_threads (1), m_max_area_ratio (3.0), m_max_vertex_count (16), m_reject_odd_polygons (false), m_text_property_name (), m_text_enlargement (-1) + : m_threads (1), m_max_area_ratio (3.0), m_max_vertex_count (16), m_reject_odd_polygons (false), m_text_property_name (), m_text_enlargement (-1), m_subcircuit_hierarchy_for_nets (false) { // .. nothing yet .. } @@ -450,6 +451,19 @@ DeepShapeStoreState::max_vertex_count () const return m_max_vertex_count; } +void +DeepShapeStoreState::set_subcircuit_hierarchy_for_nets (bool f) +{ + m_subcircuit_hierarchy_for_nets = f; +} + +bool +DeepShapeStoreState::subcircuit_hierarchy_for_nets () const +{ + return m_subcircuit_hierarchy_for_nets; +} + + // ---------------------------------------------------------------------------------- static size_t s_instance_count = 0; @@ -670,6 +684,16 @@ const tl::Variant &DeepShapeStore::text_property_name () const return m_state.text_property_name (); } +void DeepShapeStore::set_subcircuit_hierarchy_for_nets (bool f) +{ + m_state.set_subcircuit_hierarchy_for_nets (f); +} + +bool DeepShapeStore::subcircuit_hierarchy_for_nets () const +{ + return m_state.subcircuit_hierarchy_for_nets (); +} + const std::set * DeepShapeStore::breakout_cells (unsigned int layout_index) const { @@ -709,7 +733,16 @@ DeepShapeStore::has_net_builder_for (unsigned int layout_index, db::LayoutToNetl db::NetBuilder & DeepShapeStore::net_builder_for (unsigned int layout_index, db::LayoutToNetlist *l2n) { - return m_layouts [layout_index]->net_builder_for (initial_cell (layout_index), l2n); + db::NetBuilder &nb = m_layouts [layout_index]->net_builder_for (initial_cell (layout_index), l2n); + + if (subcircuit_hierarchy_for_nets ()) { + nb.set_hier_mode (db::BNH_SubcircuitCells); + nb.set_cell_name_prefix ("X$$"); // TODO: needs to be a configuration option? + } else { + nb.set_hier_mode (db::BNH_Flatten); + } + + return nb; } void DeepShapeStore::set_threads (int n) diff --git a/src/db/db/dbDeepShapeStore.h b/src/db/db/dbDeepShapeStore.h index d4a6ff297..be6e838c0 100644 --- a/src/db/db/dbDeepShapeStore.h +++ b/src/db/db/dbDeepShapeStore.h @@ -274,6 +274,9 @@ public: void add_breakout_cell (unsigned int layout_index, db::cell_index_type ci); void add_breakout_cells (unsigned int layout_index, const std::set &cc); + void set_subcircuit_hierarchy_for_nets (bool f); + bool subcircuit_hierarchy_for_nets () const; + private: int m_threads; double m_max_area_ratio; @@ -282,6 +285,7 @@ private: tl::Variant m_text_property_name; std::vector > m_breakout_cells; int m_text_enlargement; + bool m_subcircuit_hierarchy_for_nets; std::set &ensure_breakout_cells (unsigned int layout_index) { @@ -795,6 +799,20 @@ public: */ int text_enlargement () const; + /** + * @brief Sets a value indicating whether to build a subcircuit hierarchy per net + * + * This flag is used to determine the way, net subcircuit hierarchies are built: + * when true, subcells are created for subcircuits on a net. Otherwise the net + * shapes are produced flat inside the cell they appear on. + */ + void set_subcircuit_hierarchy_for_nets (bool f); + + /** + * @brief Gets a value indicating whether to build a subcircuit hierarchy per net + */ + bool subcircuit_hierarchy_for_nets () const; + /** * @brief Gets the breakout cells for a given layout * Returns 0 if there are no breakout cells for this layout. diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index 1bae80931..3969e31c8 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -1559,7 +1559,40 @@ NetBuilder::operator= (db::NetBuilder &&other) } void -NetBuilder::build_net (db::Cell &target_cell, const db::Net &net, const std::map &lmap, NetPropertyMode net_prop_mode, const tl::Variant &netname_prop) const +NetBuilder::set_net_cell_name_prefix (const char *s) +{ + m_has_net_cell_name_prefix = (s != 0); + m_net_cell_name_prefix = std::string (s ? s : ""); +} + +void +NetBuilder::set_cell_name_prefix (const char *s) +{ + bool has_cell_name_prefix = (s != 0); + std::string cell_name_prefix (s ? s : ""); + + if (has_cell_name_prefix != m_has_cell_name_prefix || cell_name_prefix != m_cell_name_prefix) { + m_reuse_table.clear (); + m_has_cell_name_prefix = has_cell_name_prefix; + m_cell_name_prefix = cell_name_prefix; + } +} + +void +NetBuilder::set_device_cell_name_prefix (const char *s) +{ + bool has_device_cell_name_prefix = (s != 0); + std::string device_cell_name_prefix (s ? s : ""); + + if (has_device_cell_name_prefix != m_has_device_cell_name_prefix || device_cell_name_prefix != m_device_cell_name_prefix) { + m_reuse_table.clear (); + m_has_device_cell_name_prefix = has_device_cell_name_prefix; + m_device_cell_name_prefix = device_cell_name_prefix; + } +} + +void +NetBuilder::prepare_build_nets () const { tl_assert (mp_target.get ()); tl_assert (mp_source.get ()); @@ -1568,6 +1601,17 @@ NetBuilder::build_net (db::Cell &target_cell, const db::Net &net, const std::map throw tl::Exception (tl::to_string (tr ("The netlist has not been extracted yet"))); } + // Resets the "initialized" flag so existing cells are reused but freshly filled + for (auto i = m_reuse_table.begin (); i != m_reuse_table.end (); ++i) { + i->second.second = false; + } +} + +void +NetBuilder::build_net (db::Cell &target_cell, const db::Net &net, const std::map &lmap, NetPropertyMode net_prop_mode, const tl::Variant &netname_prop) const +{ + prepare_build_nets (); + double mag = mp_source->internal_layout ()->dbu () / mp_target->dbu (); db::properties_id_type netname_propid = make_netname_propid (target ().properties_repository (), net_prop_mode, netname_prop, net); @@ -1577,21 +1621,13 @@ NetBuilder::build_net (db::Cell &target_cell, const db::Net &net, const std::map void NetBuilder::build_all_nets (const std::map &lmap, NetPropertyMode net_prop_mode, const tl::Variant &netname_prop) const { - tl_assert (mp_target.get ()); - tl_assert (mp_source.get ()); - build_nets (0, lmap, net_prop_mode, netname_prop); } void NetBuilder::build_nets (const std::vector *nets, const std::map &lmap, NetPropertyMode prop_mode, const tl::Variant &netname_prop) const { - tl_assert (mp_target.get ()); - tl_assert (mp_source.get ()); - - if (! mp_source->is_netlist_extracted ()) { - throw tl::Exception (tl::to_string (tr ("The netlist has not been extracted yet"))); - } + prepare_build_nets (); std::set net_set; if (nets) { @@ -1729,7 +1765,7 @@ NetBuilder::build_net_rec (db::cell_index_type ci, size_t cid, db::Cell &tc, con CellReuseTableKey cmap_key (subci, netname_propid, subcid); - cell_reuse_table_type::const_iterator cm = m_reuse_table.find (cmap_key); + cell_reuse_table_type::iterator cm = m_reuse_table.find (cmap_key); if (cm == m_reuse_table.end ()) { bool has_name_prefix = false; @@ -1747,18 +1783,24 @@ NetBuilder::build_net_rec (db::cell_index_type ci, size_t cid, db::Cell &tc, con std::string cell_name = mp_source->internal_layout ()->cell_name (subci); db::cell_index_type target_ci = target ().add_cell ((name_prefix + cell_name).c_str ()); - cm = m_reuse_table.insert (std::make_pair (cmap_key, target_ci)).first; + cm = m_reuse_table.insert (std::make_pair (cmap_key, std::make_pair (target_ci, true))).first; build_net_rec (subci, subcid, target ().cell (target_ci), lmap, 0, std::string (), netname_propid, tr_mag); } else { - cm = m_reuse_table.insert (std::make_pair (cmap_key, std::numeric_limits::max ())).first; + cm = m_reuse_table.insert (std::make_pair (cmap_key, std::make_pair (std::numeric_limits::max (), false))).first; } + } else if (!cm->second.second) { + + // initialize cell (after reuse of the net builder) + build_net_rec (subci, subcid, target ().cell (cm->second.first), lmap, 0, std::string (), netname_propid, tr_mag); + cm->second.second = true; + } - if (cm->second != std::numeric_limits::max ()) { - db::CellInstArray ci (db::CellInst (cm->second), tr_wo_mag * c->inst_trans ()); + if (cm->second.first != std::numeric_limits::max ()) { + db::CellInstArray ci (db::CellInst (cm->second.first), tr_wo_mag * c->inst_trans ()); ci.transform_into (tr_mag); target_cell->insert (ci); } diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h index 66632b9e4..1c7359cba 100644 --- a/src/db/db/dbLayoutToNetlist.h +++ b/src/db/db/dbLayoutToNetlist.h @@ -1027,33 +1027,21 @@ public: * * Pass 0 to this string value to reset it. */ - void set_net_cell_name_prefix (const char *s) - { - m_has_net_cell_name_prefix = (s != 0); - m_net_cell_name_prefix = std::string (s ? s : ""); - } + void set_net_cell_name_prefix (const char *s); /** * @brief Sets or resets the circuit cell name prefix * * Pass 0 to this string value to reset it. */ - void set_cell_name_prefix (const char *s) - { - m_has_cell_name_prefix = (s != 0); - m_cell_name_prefix = std::string (s ? s : ""); - } + void set_cell_name_prefix (const char *s); /** * @brief Sets or resets the device cell name prefix * * Pass 0 to this string value to reset it. */ - void set_device_cell_name_prefix (const char *s) - { - m_has_device_cell_name_prefix = (s != 0); - m_device_cell_name_prefix = std::string (s ? s : ""); - } + void set_device_cell_name_prefix (const char *s); /** * @brief See \LayoutToNetlist for details of this function @@ -1103,7 +1091,7 @@ private: size_t cluster_id; }; - typedef std::map cell_reuse_table_type; + typedef std::map > cell_reuse_table_type; tl::weak_ptr mp_target; db::CellMapping m_cmap; @@ -1120,6 +1108,7 @@ private: void build_net_rec (const db::Net &net, cell_index_type circuit_cell, const std::map &lmap, const std::string &add_net_cell_name_prefix, db::properties_id_type netname_propid, const ICplxTrans &tr) const; void build_net_rec (const db::Net &net, db::Cell &target_cell, const std::map &lmap, const std::string &add_net_cell_name_prefix, db::properties_id_type netname_propid, const ICplxTrans &tr) const; void build_net_rec (db::cell_index_type ci, size_t cid, db::Cell &target_cell, const std::map &lmap, const Net *net, const std::string &add_net_cell_name_prefix, db::properties_id_type netname_propid, const ICplxTrans &tr) const; + void prepare_build_nets () const; db::Layout &target () const { diff --git a/src/db/db/dbRegion.h b/src/db/db/dbRegion.h index 2ab52d087..47e687d16 100644 --- a/src/db/db/dbRegion.h +++ b/src/db/db/dbRegion.h @@ -1839,9 +1839,9 @@ public: * Netlist names will be attached as properties according to prop_mode and net_prop_name. * A net filter can be provided so that only certain nets are produced. */ - Region nets (LayoutToNetlist *l2n, NetPropertyMode prop_mode, const tl::Variant &net_prop_name, const std::vector *nets = 0) const + Region nets (LayoutToNetlist &l2n, NetPropertyMode prop_mode = db::NPM_NoProperties, const tl::Variant &net_prop_name = tl::Variant (0), const std::vector *nets = 0) const { - return Region (mp_delegate->nets (l2n, prop_mode, net_prop_name, nets)); + return Region (mp_delegate->nets (&l2n, prop_mode, net_prop_name, nets)); } /** diff --git a/src/db/db/gsiDeclDbDeepShapeStore.cc b/src/db/db/gsiDeclDbDeepShapeStore.cc index 376cf609d..ad395cda3 100644 --- a/src/db/db/gsiDeclDbDeepShapeStore.cc +++ b/src/db/db/gsiDeclDbDeepShapeStore.cc @@ -166,6 +166,21 @@ Class decl_dbDeepShapeStore ("db", "DeepShapeStore", gsi::method ("text_enlargement", &db::DeepShapeStore::text_enlargement, "@brief Gets the text enlargement value.\n" ) + + gsi::method ("subcircuit_hierarchy_for_nets=", &db::DeepShapeStore::set_subcircuit_hierarchy_for_nets, gsi::arg ("value"), + "@brief Sets a value indicating whether to build a subcircuit hierarchy per net\n" + "\n" + "\nThis flag is used to determine the way, net subcircuit hierarchies are built:\n" + "when true, subcells are created for subcircuits on a net. Otherwise the net\n" + "shapes are produced flat inside the cell they appear on.\n" + "\n" + "This attribute has been introduced in version 0.28.4" + ) + + gsi::method ("subcircuit_hierarchy_for_nets=", &db::DeepShapeStore::set_subcircuit_hierarchy_for_nets, gsi::arg ("value"), + "@brief Gets a value indicating whether to build a subcircuit hierarchy per net\n" + "See \\subcircuit_hierarchy_for_nets= for details.\n" + "\n" + "This attribute has been introduced in version 0.28.4" + ) + gsi::method ("clear_breakout_cells", &db::DeepShapeStore::clear_breakout_cells, gsi::arg ("layout_index"), "@brief Clears the breakout cells\n" "Breakout cells are a feature by which hierarchy handling can be disabled for specific cells. " diff --git a/src/db/db/gsiDeclDbRegion.cc b/src/db/db/gsiDeclDbRegion.cc index 747d0527b..4d037157c 100644 --- a/src/db/db/gsiDeclDbRegion.cc +++ b/src/db/db/gsiDeclDbRegion.cc @@ -35,6 +35,7 @@ #include "dbFillTool.h" #include "dbRegionProcessors.h" #include "dbCompoundOperation.h" +#include "dbLayoutToNetlist.h" #include "tlGlobPattern.h" #include "gsiDeclDbContainerHelpers.h" @@ -736,6 +737,12 @@ fill_region_multi (const db::Region *fr, db::Cell *cell, db::cell_index_type fil db::fill_region_repeat (cell, *fr, fill_cell_index, fc_box, row_step, column_step, fill_margin, remaining_polygons, glue_box); } +static db::Region +nets (const db::Region *region, db::LayoutToNetlist &l2n, const tl::Variant &net_prop_name, const std::vector *net_filter) +{ + return region->nets (l2n, net_prop_name.is_nil () ? db::NPM_NoProperties : db::NPM_NetNameAndIDOnly, net_prop_name, net_filter); +} + static db::Region sized_dvm (const db::Region *region, const db::Vector &dv, unsigned int mode) { @@ -3033,6 +3040,20 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "This method has been introduced in version 0.27.\n" ) + + gsi::method_ext ("nets", &nets, gsi::arg ("extracted"), gsi::arg ("net_prop_name", tl::Variant (), "nil"), gsi::arg ("net_filter"), + "@brief Pulls the net shapes from a LayoutToNetlist database\n" + "This method will pull the net shapes from the LayoutToNetlist database, provided that this " + "region was an input to the netlist extraction.\n" + "\n" + "A (net name, net id) tuple will be attached as properties to the shapes if 'net_prop_name' is given and not nil. " + "This allows generating unique properties per shape flagging the net the shape is on. This feature is good for " + "performing net-dependent booleans and DRC checks.\n" + "\n" + "A net filter can be provided with the 'net_filter' argument. If given, only nets from this " + "set are produced.\n" + "\n" + "This method was introduced in version 0.28.4" + ) + gsi::make_property_methods () , "@brief A region (a potentially complex area consisting of multiple polygons)\n" diff --git a/src/db/unit_tests/dbHierNetsProcessorTests.cc b/src/db/unit_tests/dbHierNetsProcessorTests.cc index a3c03507c..4c10e348f 100644 --- a/src/db/unit_tests/dbHierNetsProcessorTests.cc +++ b/src/db/unit_tests/dbHierNetsProcessorTests.cc @@ -44,6 +44,7 @@ TEST(0_Develop) { db::Layout ly; db::DeepShapeStore dss; + // @@@ dss.set_subcircuit_hierarchy_for_nets (true); db::LayerMap lmap; unsigned int poly = define_layer (ly, lmap, 7); @@ -84,39 +85,66 @@ TEST(0_Develop) db::Region rvia3 (db::RecursiveShapeIterator (ly, tc, via3), dss); db::Region rmetal4 (db::RecursiveShapeIterator (ly, tc, metal4), dss); - db::LayoutToNetlist l2n (&dss); + std::unique_ptr l2n (new db::LayoutToNetlist (&dss)); + EXPECT_EQ (dss.has_net_builder_for (0, l2n.get ()), false); // net extraction // Intra-layer - l2n.connect (rpoly); - l2n.connect (rcont); - l2n.connect (rmetal1); - l2n.connect (rvia1); - l2n.connect (rmetal2); - l2n.connect (rvia2); - l2n.connect (rmetal3); - l2n.connect (rvia3); - l2n.connect (rmetal4); + l2n->connect (rpoly); + l2n->connect (rcont); + l2n->connect (rmetal1); + l2n->connect (rvia1); + l2n->connect (rmetal2); + l2n->connect (rvia2); + l2n->connect (rmetal3); + l2n->connect (rvia3); + l2n->connect (rmetal4); // Inter-layer - l2n.connect (rpoly, rcont); - l2n.connect (rcont, rmetal1); - l2n.connect (rmetal1, rvia1); - l2n.connect (rvia1, rmetal2); - l2n.connect (rmetal2, rvia2); - l2n.connect (rvia2, rmetal3); - l2n.connect (rmetal3, rvia3); - l2n.connect (rvia3, rmetal4); + l2n->connect (rpoly, rcont); + l2n->connect (rcont, rmetal1); + l2n->connect (rmetal1, rvia1); + l2n->connect (rvia1, rmetal2); + l2n->connect (rmetal2, rvia2); + l2n->connect (rvia2, rmetal3); + l2n->connect (rmetal3, rvia3); + l2n->connect (rvia3, rmetal4); - l2n.extract_netlist (); +printf("@@@ extraction\n"); fflush(stdout); + l2n->extract_netlist (); - // @@@ TODO: beautify - db::Region rmetal1_nets = rmetal1.nets (&l2n, db::NPM_NetNameAndIDOnly, tl::Variant (1)); - db::Region rmetal2_nets = rmetal2.nets (&l2n, db::NPM_NetNameAndIDOnly, tl::Variant (1)); +printf("@@@ cells1=%d\n", int(dss.layout ().cells())); fflush(stdout); + db::Region rmetal1_nets = rmetal1.nets (*l2n, db::NPM_NetNameAndIDOnly, tl::Variant (1)); + EXPECT_EQ (dss.has_net_builder_for (0, l2n.get ()), true); +printf("@@@ cells2=%d\n", int(dss.layout ().cells())); fflush(stdout); + db::Region rmetal2_nets = rmetal2.nets (*l2n, db::NPM_NetNameAndIDOnly, tl::Variant (1)); +printf("@@@ cells3=%d\n", int(dss.layout ().cells())); fflush(stdout); + db::Region rmetal1_nets_more = rmetal1.nets (*l2n, db::NPM_NetNameAndIDOnly, tl::Variant (1)); +printf("@@@ cells4=%d\n", int(dss.layout ().cells())); fflush(stdout); + +// @@@ +dss.layout().set_properties(rpoly.delegate ()->deep ()->deep_layer ().layer (), db::LayerProperties(7, 0)); +dss.layout().set_properties(rcont.delegate ()->deep ()->deep_layer ().layer (), db::LayerProperties(14, 0)); +dss.layout().set_properties(rmetal1.delegate ()->deep ()->deep_layer ().layer (), db::LayerProperties(15, 0)); +dss.layout().set_properties(rvia1.delegate ()->deep ()->deep_layer ().layer (), db::LayerProperties(16, 0)); +dss.layout().set_properties(rmetal2.delegate ()->deep ()->deep_layer ().layer (), db::LayerProperties(17, 0)); +dss.layout().set_properties(rmetal1_nets.delegate ()->deep ()->deep_layer ().layer (), db::LayerProperties(115, 0)); +dss.layout().set_properties(rmetal2_nets.delegate ()->deep ()->deep_layer ().layer (), db::LayerProperties(117, 0)); +{ + db::SaveLayoutOptions options; + std::string fn ("net_outx.gds"); // @@@ + tl::OutputStream stream (fn); + db::Writer writer (options); + writer.write (dss.layout(), stream); +} +// @@@ db::Region res1 = rmetal1_nets.bool_and (rmetal2_nets, db::SamePropertiesConstraint); +printf("@@@2\n"); fflush(stdout); db::Region res2 = rmetal1_nets.bool_and (rmetal2_nets, db::DifferentPropertiesConstraint); +printf("@@@3\n"); fflush(stdout); db::Region res3 = rmetal1_nets.bool_and (rmetal2_nets, db::NoPropertyConstraint); +printf("@@@4\n"); fflush(stdout); rmetal1_nets.insert_into (&ly, tc.cell_index (), ly.insert_layer (db::LayerProperties (100, 0))); rmetal2_nets.insert_into (&ly, tc.cell_index (), ly.insert_layer (db::LayerProperties (101, 0))); @@ -124,11 +152,16 @@ TEST(0_Develop) res1.insert_into (&ly, tc.cell_index (), ly.insert_layer (db::LayerProperties (1000, 0))); res2.insert_into (&ly, tc.cell_index (), ly.insert_layer (db::LayerProperties (1001, 0))); res3.insert_into (&ly, tc.cell_index (), ly.insert_layer (db::LayerProperties (1002, 0))); +printf("@@@5\n"); fflush(stdout); + + // Test auto-unregistration + l2n.reset (0); + EXPECT_EQ (dss.has_net_builder_for (0, l2n.get ()), false); { db::SaveLayoutOptions options; - std::string fn ("net_out.gds"); // @@@ + std::string fn (dss.subcircuit_hierarchy_for_nets () ? "net_outh.gds" : "net_out.gds"); // @@@ tl::OutputStream stream (fn); db::Writer writer (options);