WIP: added ability to export nets to layouts.

This commit is contained in:
Matthias Koefferlein 2019-01-06 01:32:20 +01:00
parent bc4f9efa5d
commit ec3a3b0f8c
8 changed files with 271 additions and 1 deletions

View File

@ -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<unsigned int, const db::Region *> &lmap, const char *cell_name_prefix, std::map<std::pair<db::cell_index_type, size_t>, db::cell_index_type> &cmap) const
{
for (std::map<unsigned int, const db::Region *>::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<db::PolygonRef> &clusters = m_netex.clusters ().clusters_per_cell (circuit->cell_index ());
typedef db::connected_clusters<db::PolygonRef>::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<std::pair<db::cell_index_type, size_t>, 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<unsigned int, const db::Region *> &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<std::pair<db::cell_index_type, size_t>, 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<unsigned int, const db::Region *> &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<const Net *> 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<db::PolygonRef> &ccl = m_netex.clusters ().clusters_per_cell (c->cell_index ());
const db::local_cluster<db::PolygonRef> &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<unsigned int, const db::Region *>::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);

View File

@ -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<unsigned int, const db::Region *> &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<unsigned int, const db::Region *> &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<db::PolygonRef> &test_cluster, std::vector<db::InstElement> &rev_inst_path);
void build_net_rec (const db::Net &net, db::Layout &target, db::Cell &target_cell, const std::map<unsigned int, const db::Region *> &lmap, const char *cell_name_prefix, std::map<std::pair<db::cell_index_type, size_t>, db::cell_index_type> &cmap) const;
};
}

View File

@ -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;

View File

@ -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<unsigned int, const db::Region *> 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<unsigned int, const db::Region *> 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<unsigned int, const db::Region *> 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<unsigned int, const db::Region *> 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 ();

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.