mirror of https://github.com/KLayout/klayout.git
Some refactoring of net processor
- introduced concept of root cluster - recursive shape iterator for clusters
This commit is contained in:
parent
df44c364ea
commit
eb8abaf5a5
|
|
@ -682,8 +682,8 @@ public:
|
|||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
hc_receiver (const db::Layout &layout, db::connected_clusters<T> &cell_clusters, hier_clusters<T> &tree, const cell_clusters_box_converter<T> &cbc, const db::Connectivity &conn)
|
||||
: mp_layout (&layout), mp_tree (&tree), mp_cbc (&cbc), mp_conn (&conn)
|
||||
hc_receiver (const db::Layout &layout, const db::Cell &cell, db::connected_clusters<T> &cell_clusters, hier_clusters<T> &tree, const cell_clusters_box_converter<T> &cbc, const db::Connectivity &conn)
|
||||
: mp_layout (&layout), mp_cell (&cell), mp_tree (&tree), mp_cbc (&cbc), mp_conn (&conn)
|
||||
{
|
||||
mp_cell_clusters = &cell_clusters;
|
||||
}
|
||||
|
|
@ -739,6 +739,7 @@ public:
|
|||
|
||||
private:
|
||||
const db::Layout *mp_layout;
|
||||
const db::Cell *mp_cell;
|
||||
db::connected_clusters<T> *mp_cell_clusters;
|
||||
hier_clusters<T> *mp_tree;
|
||||
const cell_clusters_box_converter<T> *mp_cbc;
|
||||
|
|
@ -930,7 +931,7 @@ private:
|
|||
/**
|
||||
* @brief Handles a local clusters vs. the clusters of a specific child instance
|
||||
* @param c1 The local cluster
|
||||
* @param ci2 The cell index of the child cell
|
||||
* @param ci2 The cell index of the cell investigated
|
||||
* @param p2 The instantiation path to the child cell (last element is the instance to ci2)
|
||||
* @param t2 The accumulated transformation of the path
|
||||
*/
|
||||
|
|
@ -1022,10 +1023,40 @@ private:
|
|||
|
||||
ClusterInstance ci (id, *p);
|
||||
if (p == path.begin ()) {
|
||||
|
||||
// if we're attaching to a child which is root yet, we need to promote the
|
||||
// cluster to the parent in all places
|
||||
connected_clusters<T> &child_cc = mp_tree->clusters_per_cell (p->inst_ptr.cell_index ());
|
||||
if (child_cc.is_root (id)) {
|
||||
|
||||
const db::Cell &child_cell = mp_layout->cell (p->inst_ptr.cell_index ());
|
||||
for (db::Cell::parent_inst_iterator pi = child_cell.begin_parent_insts (); ! pi.at_end (); ++pi) {
|
||||
|
||||
connected_clusters<T> &parent_cc = mp_tree->clusters_per_cell (pi->parent_cell_index ());
|
||||
for (db::CellInstArray::iterator pii = pi->child_inst ().begin (); ! pii.at_end (); ++pii) {
|
||||
|
||||
ClusterInstance ci2 (id, db::InstElement (pi->child_inst (), pii));
|
||||
if (mp_cell->cell_index () != pi->parent_cell_index () || ci != ci2) {
|
||||
|
||||
id_type id_dummy = parent_cc.insert_dummy ();
|
||||
parent_cc.add_connection (id_dummy, ci2);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
child_cc.reset_root (id);
|
||||
|
||||
}
|
||||
|
||||
return ci;
|
||||
|
||||
}
|
||||
|
||||
connected_clusters<T> &target_cc = mp_tree->clusters_per_cell (p [-1].inst_ptr.cell_index ());
|
||||
db::cell_index_type pci = p [-1].inst_ptr.cell_index ();
|
||||
connected_clusters<T> &target_cc = mp_tree->clusters_per_cell (pci);
|
||||
id_type parent_cluster = target_cc.find_cluster_with_connection (ci);
|
||||
|
||||
if (parent_cluster > 0) {
|
||||
|
|
@ -1035,13 +1066,43 @@ private:
|
|||
|
||||
} else {
|
||||
|
||||
id_type id_new = 0;
|
||||
|
||||
// if we're attaching to a child which is root yet, we need to promote the
|
||||
// cluster to the parent in all places
|
||||
connected_clusters<T> &child_cc = mp_tree->clusters_per_cell (p->inst_ptr.cell_index ());
|
||||
if (child_cc.is_root (id)) {
|
||||
|
||||
const db::Cell &child_cell = mp_layout->cell (p->inst_ptr.cell_index ());
|
||||
for (db::Cell::parent_inst_iterator pi = child_cell.begin_parent_insts (); ! pi.at_end (); ++pi) {
|
||||
|
||||
connected_clusters<T> &parent_cc = mp_tree->clusters_per_cell (pi->parent_cell_index ());
|
||||
for (db::CellInstArray::iterator pii = pi->child_inst ().begin (); ! pii.at_end (); ++pii) {
|
||||
|
||||
id_type id_dummy = parent_cc.insert_dummy ();
|
||||
ClusterInstance ci2 (id, db::InstElement (pi->child_inst (), pii));
|
||||
parent_cc.add_connection (id_dummy, ci2);
|
||||
|
||||
if (pci == pi->parent_cell_index () && ci == ci2) {
|
||||
id_new = id_dummy;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
child_cc.reset_root (id);
|
||||
|
||||
}
|
||||
|
||||
// no parent -> create vertical connector
|
||||
id = target_cc.insert_dummy ();
|
||||
target_cc.add_connection (id, ci);
|
||||
id = id_new;
|
||||
tl_assert (id != 0);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1165,7 +1226,7 @@ hier_clusters<T>::build_hier_connections (cell_clusters_box_converter<T> &cbc, c
|
|||
|
||||
// NOTE: this is a receiver for both the child-to-child and
|
||||
// local to child interactions.
|
||||
hc_receiver<T> rec (layout, local, *this, cbc, conn);
|
||||
hc_receiver<T> rec (layout, cell, local, *this, cbc, conn);
|
||||
cell_inst_clusters_box_converter<T> cibc (cbc);
|
||||
|
||||
// The box scanner needs pointers so we have to first store the instances
|
||||
|
|
@ -1241,70 +1302,131 @@ hier_clusters<T>::clusters_per_cell (db::cell_index_type cell_index)
|
|||
return c->second;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static
|
||||
void put_or_propagate (const hier_clusters<T> &hc, incoming_cluster_connections<T> &inc, size_t cluster_id, const local_cluster<T> &cluster, db::Layout &layout, db::cell_index_type ci, const std::map<unsigned int, unsigned int> &lm, const db::ICplxTrans &trans)
|
||||
template <class Shape, class Trans> void insert_transformed (db::Layout &layout, db::Shapes &shapes, const Shape &s, const Trans &t);
|
||||
|
||||
template <class Trans> void insert_transformed (db::Layout &layout, db::Shapes &shapes, const db::PolygonRef &s, const Trans &t)
|
||||
{
|
||||
db::Cell &target_cell = layout.cell (ci);
|
||||
|
||||
if (cluster_id > 0 && inc.has_incoming (ci, cluster_id)) {
|
||||
|
||||
typedef std::pair<db::cell_index_type, db::InstElement> reference_type;
|
||||
std::map<reference_type, bool> references;
|
||||
|
||||
for (db::Cell::parent_inst_iterator pi = target_cell.begin_parent_insts (); ! pi.at_end (); ++pi) {
|
||||
db::Instance i = pi->child_inst ();
|
||||
for (db::CellInstArray::iterator ii = i.cell_inst ().begin (); ! ii.at_end (); ++ii) {
|
||||
references.insert (std::make_pair (reference_type ((*pi).parent_cell_index (), db::InstElement (i, ii)), false));
|
||||
}
|
||||
}
|
||||
|
||||
const typename incoming_cluster_connections<T>::incoming_connections &connections = inc.incoming (ci, cluster_id);
|
||||
for (typename incoming_cluster_connections<T>::incoming_connections::const_iterator x = connections.begin (); x != connections.end (); ++x) {
|
||||
typename std::map<reference_type, bool>::iterator r = references.find (reference_type (x->parent_cell (), x->inst ()));
|
||||
if (r != references.end () && ! r->second) {
|
||||
put_or_propagate (hc, inc, x->parent_cluster_id (), cluster, layout, r->first.first, lm, r->first.second.complex_trans () * trans);
|
||||
r->second = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (typename std::map<reference_type, bool>::const_iterator r = references.begin (); r != references.end (); ++r) {
|
||||
if (! r->second) {
|
||||
put_or_propagate (hc, inc, 0, cluster, layout, r->first.first, lm, r->first.second.complex_trans () * trans);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
for (typename std::map<unsigned int, unsigned int>::const_iterator m = lm.begin (); m != lm.end (); ++m) {
|
||||
db::Shapes shapes;
|
||||
for (typename local_cluster<T>::shape_iterator s = cluster.begin (m->first); ! s.at_end (); ++s) {
|
||||
shapes.insert (*s);
|
||||
}
|
||||
tl::ident_map<db::properties_id_type> pm;
|
||||
target_cell.shapes (m->second).insert_transformed (shapes, trans, pm);
|
||||
}
|
||||
|
||||
db::Polygon poly = s.obj ();
|
||||
poly.transform (s.trans ());
|
||||
if (! t.is_unity ()) {
|
||||
poly.transform (t);
|
||||
}
|
||||
shapes.insert (db::PolygonRef (poly, layout.shape_repository ()));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
hier_clusters<T>::return_to_hierarchy (db::Layout &layout, db::Cell &cell, const std::map<unsigned int, unsigned int> &lm) const
|
||||
hier_clusters<T>::return_to_hierarchy (db::Layout &layout, const std::map<unsigned int, unsigned int> &lm) const
|
||||
{
|
||||
incoming_cluster_connections<T> inc (layout, cell, *this);
|
||||
|
||||
for (db::Layout::bottom_up_iterator c = layout.begin_bottom_up (); c != layout.end_bottom_up (); ++c) {
|
||||
|
||||
const db::connected_clusters<T> &cc = clusters_per_cell (*c);
|
||||
for (typename db::connected_clusters<T>::const_iterator lc = cc.begin (); lc != cc.end (); ++lc) {
|
||||
put_or_propagate (*this, inc, lc->id (), *lc, layout, *c, lm, db::ICplxTrans ());
|
||||
db::Cell &target_cell = layout.cell (*c);
|
||||
|
||||
for (typename db::connected_clusters<T>::all_iterator lc = cc.begin_all (); ! lc.at_end (); ++lc) {
|
||||
|
||||
if (cc.is_root (*lc)) {
|
||||
|
||||
for (typename std::map<unsigned int, unsigned int>::const_iterator m = lm.begin (); m != lm.end (); ++m) {
|
||||
|
||||
db::Shapes &shapes = target_cell.shapes (m->second);
|
||||
|
||||
for (recursive_cluster_shape_iterator<T> si (*this, m->first, *c, *lc); ! si.at_end (); ++si) {
|
||||
insert_transformed (layout, shapes, *si, si.trans ());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// explicit instantiations
|
||||
template class DB_PUBLIC hier_clusters<db::PolygonRef>;
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// recursive_cluster_shape_iterator implementation
|
||||
|
||||
template <class T>
|
||||
recursive_cluster_shape_iterator<T>::recursive_cluster_shape_iterator (const hier_clusters<T> &hc, unsigned int layer, db::cell_index_type ci, typename local_cluster<T>::id_type id)
|
||||
: mp_hc (&hc), m_layer (layer), m_id (id)
|
||||
{
|
||||
down (ci, id, db::ICplxTrans ());
|
||||
|
||||
while (m_shape_iter.at_end () && ! m_conn_iter_stack.empty ()) {
|
||||
next_conn ();
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
recursive_cluster_shape_iterator<T> &recursive_cluster_shape_iterator<T>::operator++ ()
|
||||
{
|
||||
++m_shape_iter;
|
||||
|
||||
while (m_shape_iter.at_end () && ! m_conn_iter_stack.empty ()) {
|
||||
next_conn ();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void recursive_cluster_shape_iterator<T>::next_conn ()
|
||||
{
|
||||
if (m_conn_iter_stack.back ().first != m_conn_iter_stack.back ().second) {
|
||||
|
||||
const ClusterInstance &cli = *m_conn_iter_stack.back ().first;
|
||||
down (cli.inst ().inst_ptr.cell_index (), cli.id (), cli.inst ().complex_trans ());
|
||||
|
||||
} else {
|
||||
|
||||
while (m_conn_iter_stack.back ().first == m_conn_iter_stack.back ().second) {
|
||||
|
||||
up ();
|
||||
if (m_conn_iter_stack.empty ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
++m_conn_iter_stack.back ().first;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void recursive_cluster_shape_iterator<T>::up ()
|
||||
{
|
||||
m_conn_iter_stack.pop_back ();
|
||||
m_trans_stack.pop_back ();
|
||||
m_cell_index_stack.pop_back ();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void recursive_cluster_shape_iterator<T>::down (db::cell_index_type ci, typename db::local_cluster<T>::id_type id, const db::ICplxTrans &t)
|
||||
{
|
||||
const connected_clusters<T> &clusters = mp_hc->clusters_per_cell (ci);
|
||||
const typename connected_clusters<T>::connections_type &conn = clusters.connections_for_cluster (id);
|
||||
|
||||
if (! m_trans_stack.empty ()) {
|
||||
m_trans_stack.push_back (m_trans_stack.back () * t);
|
||||
} else {
|
||||
m_trans_stack.push_back (t);
|
||||
}
|
||||
|
||||
m_cell_index_stack.push_back (ci);
|
||||
m_conn_iter_stack.push_back (std::make_pair (conn.begin (), conn.end ()));
|
||||
|
||||
const local_cluster<T> &cluster = mp_hc->clusters_per_cell (cell_index ()).cluster_by_id (cluster_id ());
|
||||
m_shape_iter = cluster.begin (m_layer);
|
||||
}
|
||||
|
||||
// explicit instantiations
|
||||
template class DB_PUBLIC recursive_cluster_shape_iterator<db::PolygonRef>;
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// incoming_cluster_connections implementation
|
||||
|
||||
|
|
|
|||
|
|
@ -229,6 +229,7 @@ template <class T>
|
|||
class DB_PUBLIC local_clusters
|
||||
{
|
||||
public:
|
||||
typedef typename local_cluster<T>::id_type id_type;
|
||||
typedef typename local_cluster<T>::box_type box_type;
|
||||
typedef db::box_tree<box_type, local_cluster<T>, local_cluster_box_convert<T> > tree_type;
|
||||
typedef typename tree_type::touching_iterator touching_iterator;
|
||||
|
|
@ -372,6 +373,14 @@ public:
|
|||
return m_id == other.m_id && m_inst == other.m_inst;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inequality
|
||||
*/
|
||||
bool operator!= (const ClusterInstance &other) const
|
||||
{
|
||||
return ! operator== (other);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Less operator
|
||||
*/
|
||||
|
|
@ -434,12 +443,20 @@ private:
|
|||
|
||||
/**
|
||||
* @brief Local clusters with connections to clusters from child cells
|
||||
*
|
||||
* Clusters can get connected. There are incoming connections (from above the hierarchy)
|
||||
* and outgoing connections (down to a child cell).
|
||||
*
|
||||
* "root" clusters are some that don't have incoming connections. There are only
|
||||
* root clusters or clusters which are connected from every parent cell. There are no
|
||||
* "half connected" clusters.
|
||||
*/
|
||||
template <class T>
|
||||
class DB_PUBLIC connected_clusters
|
||||
: public local_clusters<T>
|
||||
{
|
||||
public:
|
||||
typedef typename local_clusters<T>::id_type id_type;
|
||||
typedef std::list<ClusterInstance> connections_type;
|
||||
typedef typename local_clusters<T>::box_type box_type;
|
||||
typedef connected_clusters_iterator<T> all_iterator;
|
||||
|
|
@ -507,11 +524,29 @@ public:
|
|||
return m_connections.end ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns true, if the given cluster ID is a root cluster
|
||||
*/
|
||||
bool is_root (id_type id) const
|
||||
{
|
||||
return m_connected_clusters.find (id) == m_connected_clusters.end ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resets the root status of a cluster
|
||||
* CAUTION: don't call this method unless you know what you're doing.
|
||||
*/
|
||||
void reset_root (id_type id)
|
||||
{
|
||||
m_connected_clusters.insert (id);
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename> friend class connected_clusters_iterator;
|
||||
|
||||
std::map<typename local_cluster<T>::id_type, connections_type> m_connections;
|
||||
std::map<id_type, connections_type> m_connections;
|
||||
std::map<ClusterInstance, typename local_cluster<T>::id_type> m_rev_connections;
|
||||
std::set<id_type> m_connected_clusters;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
|
|
@ -573,7 +608,7 @@ public:
|
|||
* The backannotation process usually involves propagation of shapes up in the hierarchy
|
||||
* to resolve variants.
|
||||
*/
|
||||
void return_to_hierarchy (db::Layout &layout, db::Cell &cell, const std::map<unsigned int, unsigned int> &lm) const;
|
||||
void return_to_hierarchy (db::Layout &layout, const std::map<unsigned int, unsigned int> &lm) const;
|
||||
|
||||
/**
|
||||
* @brief Clears this collection
|
||||
|
|
@ -589,6 +624,100 @@ private:
|
|||
std::map<db::cell_index_type, connected_clusters<T> > m_per_cell_clusters;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A recursive shape iterator for the shapes of a cluster
|
||||
*
|
||||
* This iterator will deliver the shapes of a cluster including the shapes for the
|
||||
* connected child clusters.
|
||||
*
|
||||
* This iterator applies to one layer.
|
||||
*/
|
||||
template <class T>
|
||||
class DB_PUBLIC recursive_cluster_shape_iterator
|
||||
{
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef const T &reference;
|
||||
typedef const T *pointer;
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
recursive_cluster_shape_iterator (const hier_clusters<T> &hc, unsigned int layer, db::cell_index_type ci, typename local_cluster<T>::id_type id);
|
||||
|
||||
/**
|
||||
* @brief Returns a value indicating whether there are any more shapes
|
||||
*/
|
||||
bool at_end () const
|
||||
{
|
||||
return m_shape_iter.at_end ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the shape (untransformed)
|
||||
*/
|
||||
reference operator* () const
|
||||
{
|
||||
return *m_shape_iter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the shape pointer (untransformed)
|
||||
*/
|
||||
pointer operator-> () const
|
||||
{
|
||||
return m_shape_iter.operator-> ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the transformation applicable for transforming the shape to the root cluster
|
||||
*/
|
||||
const db::ICplxTrans &trans () const
|
||||
{
|
||||
return m_trans_stack.back ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the cell index the shape lives in
|
||||
*/
|
||||
db::cell_index_type cell_index () const
|
||||
{
|
||||
return m_cell_index_stack.back ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the id of the current cluster
|
||||
*/
|
||||
typename db::local_cluster<T>::id_type cluster_id () const
|
||||
{
|
||||
if (m_conn_iter_stack.size () <= 1) {
|
||||
return m_id;
|
||||
} else {
|
||||
return m_conn_iter_stack [m_conn_iter_stack.size () - 2].first->id ();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Increment operator
|
||||
*/
|
||||
recursive_cluster_shape_iterator &operator++ ();
|
||||
|
||||
private:
|
||||
typedef typename db::connected_clusters<T>::connections_type connections_type;
|
||||
|
||||
const hier_clusters<T> *mp_hc;
|
||||
std::vector<db::ICplxTrans> m_trans_stack;
|
||||
std::vector<db::cell_index_type> m_cell_index_stack;
|
||||
std::vector<std::pair<typename connections_type::const_iterator, typename connections_type::const_iterator> > m_conn_iter_stack;
|
||||
typename db::local_cluster<T>::shape_iterator m_shape_iter;
|
||||
unsigned int m_layer;
|
||||
typename db::local_cluster<T>::id_type m_id;
|
||||
|
||||
void next_conn ();
|
||||
void up ();
|
||||
void down (db::cell_index_type ci, typename db::local_cluster<T>::id_type id, const db::ICplxTrans &t);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A connection to a cluster from a parent cluster
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -515,6 +515,10 @@ static void run_hc_test (tl::TestBase *_this, const std::string &file, const std
|
|||
const db::connected_clusters<db::PolygonRef> &clusters = hc.clusters_per_cell (*td);
|
||||
for (db::connected_clusters<db::PolygonRef>::all_iterator c = clusters.begin_all (); ! c.at_end (); ++c) {
|
||||
|
||||
if (! clusters.is_root (*c)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
net_layers.push_back (std::make_pair (0, ly.insert_layer ()));
|
||||
|
||||
unsigned int lout = net_layers.back ().second;
|
||||
|
|
@ -601,7 +605,7 @@ static void run_hc_test_with_backannotation (tl::TestBase *_this, const std::str
|
|||
lm[l1] = ly.insert_layer (db::LayerProperties (101, 0));
|
||||
lm[l2] = ly.insert_layer (db::LayerProperties (102, 0));
|
||||
lm[l3] = ly.insert_layer (db::LayerProperties (103, 0));
|
||||
hc.return_to_hierarchy (ly, ly.cell (*ly.begin_top_down ()), lm);
|
||||
hc.return_to_hierarchy (ly, lm);
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/" + au_file);
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue