diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index d9c3052b4..af2026460 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -287,6 +287,119 @@ db::Region *LayoutToNetlist::shapes_of_net (const db::Net &net, const db::Region return res.release (); } +void +LayoutToNetlist::build_net_rec (const db::Net &net, db::Layout &target, db::Cell &target_cell, const std::map &lmap, const char *cell_name_prefix, std::map, db::cell_index_type> &cmap) const +{ + for (std::map::const_iterator l = lmap.begin (); l != lmap.end (); ++l) { + shapes_of_net (net, *l->second, false, target_cell.shapes (l->first)); + } + + if (! cell_name_prefix) { + return; + } + + const db::Circuit *circuit = net.circuit (); + tl_assert (circuit != 0); + + const db::connected_clusters &clusters = m_netex.clusters ().clusters_per_cell (circuit->cell_index ()); + typedef db::connected_clusters::connections_type connections_type; + const connections_type &connections = clusters.connections_for_cluster (net.cluster_id ()); + for (connections_type::const_iterator c = connections.begin (); c != connections.end (); ++c) { + + db::cell_index_type ci = c->inst ().inst_ptr.cell_index (); + const db::Circuit *subcircuit = mp_netlist->circuit_by_cell_index (ci); + tl_assert (subcircuit != 0); + + const db::Net *subnet = subcircuit->net_by_cluster_id (c->id ()); + tl_assert (subnet != 0); + + std::map, db::cell_index_type>::const_iterator cm = cmap.find (std::make_pair (ci, c->id ())); + if (cm == cmap.end ()) { + + db::cell_index_type target_ci = target.add_cell ((std::string (cell_name_prefix) + subcircuit->name ()).c_str ()); + cm = cmap.insert (std::make_pair (std::make_pair (ci, c->id ()), target_ci)).first; + + build_net_rec (*subnet, target, target.cell (target_ci), lmap, cell_name_prefix, cmap); + + } + + target_cell.insert (db::CellInstArray (db::CellInst (cm->second), c->inst ().complex_trans ())); + + } +} + +void +LayoutToNetlist::build_net (const db::Net &net, db::Layout &target, db::Cell &target_cell, const std::map &lmap, const char *cell_name_prefix) const +{ + if (! m_netlist_extracted) { + throw tl::Exception (tl::to_string (tr ("The netlist has not been extracted yet"))); + } + + std::map, db::cell_index_type> cell_map; + cell_map.insert (std::make_pair (std::make_pair (net.circuit ()->cell_index (), net.cluster_id ()), target_cell.cell_index ())); + + build_net_rec (net, target, target_cell, lmap, cell_name_prefix, cell_map); +} + +void +LayoutToNetlist::build_all_nets (const db::CellMapping &cmap, db::Layout &target, const std::map &lmap, const char *net_cell_name_prefix, const char *circuit_cell_name_prefix) const +{ + if (! m_netlist_extracted) { + throw tl::Exception (tl::to_string (tr ("The netlist has not been extracted yet"))); + } + + const db::Netlist *netlist = mp_netlist.get (); + for (db::Netlist::const_circuit_iterator c = netlist->begin_circuits (); c != netlist->end_circuits (); ++c) { + + if (! cmap.has_mapping (c->cell_index ())) { + continue; + } + + std::set excluded_nets; + if (circuit_cell_name_prefix) { + for (db::Circuit::const_pin_iterator p = c->begin_pins (); p != c->end_pins (); ++p) { + excluded_nets.insert (c->net_for_pin (p->id ())); + } + } + + db::cell_index_type target_ci = cmap.cell_mapping (c->cell_index ()); + + for (db::Circuit::const_net_iterator n = c->begin_nets (); n != c->end_nets (); ++n) { + + if (excluded_nets.find (n.operator-> ()) == excluded_nets.end ()) { + + const db::connected_clusters &ccl = m_netex.clusters ().clusters_per_cell (c->cell_index ()); + const db::local_cluster &cl = ccl.cluster_by_id (n->cluster_id ()); + + bool any_connections = ! ccl.connections_for_cluster (n->cluster_id ()).empty (); + + bool any_shapes = false; + for (std::map::const_iterator m = lmap.begin (); m != lmap.end () && !any_shapes; ++m) { + any_shapes = ! cl.begin (layer_of (*m->second)).at_end (); + } + + if (any_shapes || (circuit_cell_name_prefix && any_connections)) { + + db::cell_index_type net_ci = target_ci; + + if (net_cell_name_prefix) { + + db::Cell &tc = target.cell (target_ci); + net_ci = target.add_cell ((std::string (net_cell_name_prefix) + n->expanded_name ()).c_str ()); + tc.insert (db::CellInstArray (db::CellInst (net_ci), db::Trans ())); + + } + + build_net (*n, target, target.cell (net_ci), lmap, circuit_cell_name_prefix); + + } + + } + } + + } +} + db::Net *LayoutToNetlist::probe_net (const db::Region &of_region, const db::DPoint &point) { return probe_net (of_region, db::CplxTrans (internal_layout ()->dbu ()).inverted () * point); diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h index 4efaf4294..7e7f40689 100644 --- a/src/db/db/dbLayoutToNetlist.h +++ b/src/db/db/dbLayoutToNetlist.h @@ -235,6 +235,52 @@ public: */ void shapes_of_net (const db::Net &net, const db::Region &of_layer, bool recursive, db::Shapes &to) const; + /** + * @brief Builds a net representation in the given layout and cell + * + * This method has two modes: recursive and top-level mode. In recursive mode, + * it will create a proper hierarchy below the given target cell to hold all subcircuits the + * net connects to. It will copy the net's parts from this subcircuits into these cells. + * + * In top-level mode, only the shapes from the net inside it's circuit are copied to + * the given target cell. No other cells are created. + * + * Recursive mode is picked when a cell name prefix is given. The new cells will be + * named like cell_name_prefix + circuit name. + * + * @param target The target layout + * @param target_cell The target cell + * @param lmap Target layer indexes (keys) and net regions (values) + * @param cell_name_prefix Chooses recursive mode if non-null + */ + void build_net (const db::Net &net, db::Layout &target, db::Cell &target_cell, const std::map &lmap, const char *cell_name_prefix) const; + + /** + * @brief Builds a full hierarchical representation of the nets + * + * This method copies all nets into cells corresponding to the circuits. It uses the cmap + * object to determine the target cell (create them with "cell_mapping_into" or "const_cell_mapping_into"). + * If no mapping is requested, the specific circuit it skipped. + * + * The method has two net annotation modes: + * * No annotation (net_cell_name_prefix == 0): the shapes will be put into the target cell simply + * * Individual subcells per net (net_cell_name_prefix != 0): for each net, a subcell is created + * and the net shapes will be put there (name of the subcell = net_cell_name_prefix + net name). + * + * In addition, net hierarchy is covered in two ways: + * * No connection indicated (circuit_cell_name_prefix == 0: the net shapes are simply put into their + * respective circuits. The connections are not indicated. + * * Subnet hierarchy (circuit_cell_name_prefix != 0): for each root net, a full hierarchy is built + * to accomodate the subnets (see build_net in recursive mode). + * + * @param cmap The mapping of internal layout to target layout for the circuit mapping + * @param target The target layout + * @param lmap Target layer indexes (keys) and net regions (values) + * @param circuit_cell_name_prefix See method description + * @param net_cell_name_prefix See method description + */ + void build_all_nets (const db::CellMapping &cmap, db::Layout &target, const std::map &lmap, const char *net_cell_name_prefix, const char *circuit_cell_name_prefix) const; + /** * @brief Finds the net by probing a specific location on the given layer * @@ -271,6 +317,7 @@ private: bool m_netlist_extracted; size_t search_net (const db::ICplxTrans &trans, const db::Cell *cell, const db::local_cluster &test_cluster, std::vector &rev_inst_path); + void build_net_rec (const db::Net &net, db::Layout &target, db::Cell &target_cell, const std::map &lmap, const char *cell_name_prefix, std::map, db::cell_index_type> &cmap) const; }; } diff --git a/src/db/db/dbNetlist.h b/src/db/db/dbNetlist.h index 73ea82d42..4c689389d 100644 --- a/src/db/db/dbNetlist.h +++ b/src/db/db/dbNetlist.h @@ -1534,7 +1534,7 @@ public: /** * @brief Returns true, if the net is an external net * - * External nets are net which are connected to an outgoing pin. + * External nets are nets which are connected to an outgoing pin. */ bool is_external_net (const db::Net *net) const; diff --git a/src/db/unit_tests/dbLayoutToNetlistTests.cc b/src/db/unit_tests/dbLayoutToNetlistTests.cc index 10ecc840c..f63bdbf78 100644 --- a/src/db/unit_tests/dbLayoutToNetlistTests.cc +++ b/src/db/unit_tests/dbLayoutToNetlistTests.cc @@ -382,6 +382,116 @@ TEST(1_Basic) EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (2.6, 1.0))), "RINGO:$I39"); EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (6.4, 1.0))), "RINGO:$I2"); + // test build_all_nets + + { + db::Layout ly2; + ly2.dbu (ly.dbu ()); + db::Cell &top2 = ly2.cell (ly2.add_cell ("TOP")); + + db::CellMapping cm = l2n.cell_mapping_into (ly2, top2); + + std::map lmap; + lmap [ly2.insert_layer (db::LayerProperties (10, 0))] = &rpsd; + lmap [ly2.insert_layer (db::LayerProperties (11, 0))] = &rnsd; + lmap [ly2.insert_layer (db::LayerProperties (3, 0)) ] = rpoly.get (); + lmap [ly2.insert_layer (db::LayerProperties (4, 0)) ] = rdiff_cont.get (); + lmap [ly2.insert_layer (db::LayerProperties (5, 0)) ] = rpoly_cont.get (); + lmap [ly2.insert_layer (db::LayerProperties (6, 0)) ] = rmetal1.get (); + lmap [ly2.insert_layer (db::LayerProperties (7, 0)) ] = rvia1.get (); + lmap [ly2.insert_layer (db::LayerProperties (8, 0)) ] = rmetal2.get (); + + l2n.build_all_nets (cm, ly2, lmap, 0, 0); + + std::string au = tl::testsrc (); + au = tl::combine_path (au, "testdata"); + au = tl::combine_path (au, "algo"); + au = tl::combine_path (au, "device_extract_au1_rebuild_ff.gds"); + + db::compare_layouts (_this, ly2, au); + } + + { + db::Layout ly2; + ly2.dbu (ly.dbu ()); + db::Cell &top2 = ly2.cell (ly2.add_cell ("TOP")); + + db::CellMapping cm = l2n.cell_mapping_into (ly2, top2); + + std::map lmap; + lmap [ly2.insert_layer (db::LayerProperties (10, 0))] = &rpsd; + lmap [ly2.insert_layer (db::LayerProperties (11, 0))] = &rnsd; + lmap [ly2.insert_layer (db::LayerProperties (3, 0)) ] = rpoly.get (); + lmap [ly2.insert_layer (db::LayerProperties (4, 0)) ] = rdiff_cont.get (); + lmap [ly2.insert_layer (db::LayerProperties (5, 0)) ] = rpoly_cont.get (); + lmap [ly2.insert_layer (db::LayerProperties (6, 0)) ] = rmetal1.get (); + lmap [ly2.insert_layer (db::LayerProperties (7, 0)) ] = rvia1.get (); + lmap [ly2.insert_layer (db::LayerProperties (8, 0)) ] = rmetal2.get (); + + l2n.build_all_nets (cm, ly2, lmap, "NET_", 0); + + std::string au = tl::testsrc (); + au = tl::combine_path (au, "testdata"); + au = tl::combine_path (au, "algo"); + au = tl::combine_path (au, "device_extract_au1_rebuild_nf.gds"); + + db::compare_layouts (_this, ly2, au); + } + + { + db::Layout ly2; + ly2.dbu (ly.dbu ()); + db::Cell &top2 = ly2.cell (ly2.add_cell ("TOP")); + + db::CellMapping cm = l2n.cell_mapping_into (ly2, top2); + + std::map lmap; + lmap [ly2.insert_layer (db::LayerProperties (10, 0))] = &rpsd; + lmap [ly2.insert_layer (db::LayerProperties (11, 0))] = &rnsd; + lmap [ly2.insert_layer (db::LayerProperties (3, 0)) ] = rpoly.get (); + lmap [ly2.insert_layer (db::LayerProperties (4, 0)) ] = rdiff_cont.get (); + lmap [ly2.insert_layer (db::LayerProperties (5, 0)) ] = rpoly_cont.get (); + lmap [ly2.insert_layer (db::LayerProperties (6, 0)) ] = rmetal1.get (); + lmap [ly2.insert_layer (db::LayerProperties (7, 0)) ] = rvia1.get (); + lmap [ly2.insert_layer (db::LayerProperties (8, 0)) ] = rmetal2.get (); + + l2n.build_all_nets (cm, ly2, lmap, 0, "CIRCUIT_"); + + std::string au = tl::testsrc (); + au = tl::combine_path (au, "testdata"); + au = tl::combine_path (au, "algo"); + au = tl::combine_path (au, "device_extract_au1_rebuild_fr.gds"); + + db::compare_layouts (_this, ly2, au); + } + + { + db::Layout ly2; + ly2.dbu (ly.dbu ()); + db::Cell &top2 = ly2.cell (ly2.add_cell ("TOP")); + + db::CellMapping cm = l2n.cell_mapping_into (ly2, top2); + + std::map lmap; + lmap [ly2.insert_layer (db::LayerProperties (10, 0))] = &rpsd; + lmap [ly2.insert_layer (db::LayerProperties (11, 0))] = &rnsd; + lmap [ly2.insert_layer (db::LayerProperties (3, 0)) ] = rpoly.get (); + lmap [ly2.insert_layer (db::LayerProperties (4, 0)) ] = rdiff_cont.get (); + lmap [ly2.insert_layer (db::LayerProperties (5, 0)) ] = rpoly_cont.get (); + lmap [ly2.insert_layer (db::LayerProperties (6, 0)) ] = rmetal1.get (); + lmap [ly2.insert_layer (db::LayerProperties (7, 0)) ] = rvia1.get (); + lmap [ly2.insert_layer (db::LayerProperties (8, 0)) ] = rmetal2.get (); + + l2n.build_all_nets (cm, ly2, lmap, "NET_", "CIRCUIT_"); + + std::string au = tl::testsrc (); + au = tl::combine_path (au, "testdata"); + au = tl::combine_path (au, "algo"); + au = tl::combine_path (au, "device_extract_au1_rebuild_nr.gds"); + + db::compare_layouts (_this, ly2, au); + } + // doesn't do anything here, but we test that this does not destroy anything: l2n.netlist ()->combine_devices (); diff --git a/testdata/algo/device_extract_au1_rebuild_ff.gds b/testdata/algo/device_extract_au1_rebuild_ff.gds new file mode 100644 index 000000000..afbbb5092 Binary files /dev/null and b/testdata/algo/device_extract_au1_rebuild_ff.gds differ diff --git a/testdata/algo/device_extract_au1_rebuild_fr.gds b/testdata/algo/device_extract_au1_rebuild_fr.gds new file mode 100644 index 000000000..093c327a6 Binary files /dev/null and b/testdata/algo/device_extract_au1_rebuild_fr.gds differ diff --git a/testdata/algo/device_extract_au1_rebuild_nf.gds b/testdata/algo/device_extract_au1_rebuild_nf.gds new file mode 100644 index 000000000..56af23394 Binary files /dev/null and b/testdata/algo/device_extract_au1_rebuild_nf.gds differ diff --git a/testdata/algo/device_extract_au1_rebuild_nr.gds b/testdata/algo/device_extract_au1_rebuild_nr.gds new file mode 100644 index 000000000..ef77178c5 Binary files /dev/null and b/testdata/algo/device_extract_au1_rebuild_nr.gds differ