From d2c2a875ddc88c8613f4d4580d4ea5b43e62e46c Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 13 Feb 2022 23:39:09 +0100 Subject: [PATCH 1/9] Removed debug output --- src/db/db/dbHierProcessor.cc | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/db/db/dbHierProcessor.cc b/src/db/db/dbHierProcessor.cc index 3c9d1215e..a54b9676f 100644 --- a/src/db/db/dbHierProcessor.cc +++ b/src/db/db/dbHierProcessor.cc @@ -1063,11 +1063,6 @@ private: void collect_instance_interactions (const db::CellInstArray *inst1, const db::CellInstArray *inst2) { -#if 0 -printf("@@@ check instance interactions %s (#%d, %s) <-> %s (#%d, %s)\n", - mp_subject_layout->cell_name (inst1->object ().cell_index ()), int (inst1->size ()), (inst1->bbox(db::box_convert (*mp_subject_layout)).to_string()).c_str(), - mp_intruder_layout->cell_name (inst2->object ().cell_index ()), int (inst2->size ()), (inst2->bbox(db::box_convert (*mp_intruder_layout)).to_string()).c_str()); // @@@ -#endif // TODO: this algorithm is not in particular effective for identical arrays const db::Cell &cell1 = mp_subject_layout->cell (inst1->object ().cell_index ()); @@ -1076,9 +1071,6 @@ printf("@@@ check instance interactions %s (#%d, %s) <-> %s (#%d, %s)\n", std::unordered_map > > interactions_cache; -#if 0 -printf("@@@ -> #%d\n", int(inst1->size())); -#endif for (db::CellInstArray::iterator n = inst1->begin (); ! n.at_end (); ++n) { db::ICplxTrans tn1 = inst1->complex_trans (*n); @@ -1482,9 +1474,6 @@ void local_processor::compute_contexts (local_processor_contexts::context_key_type &intruders, db::Coord dist) const { -#if 0 // @@@ -printf("@@@ --- compute_contexts (%s @ %s)\n", mp_subject_layout->cell_name (subject_cell->cell_index ()), subject_cell_inst.to_string().c_str()); fflush(stdout); -#endif CRONOLOGY_COLLECTION_BRACKET(event_compute_contexts) if (tl::verbosity () >= m_base_verbosity + 20) { From e9d86822df8333445b24a95c6556d680516bc775 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 18 Feb 2022 00:03:14 +0100 Subject: [PATCH 2/9] Scale and snap improvements * edge and edge pair support * property support * no expanding of on-grid arrays * more inline processing, better performance --- src/db/db/dbArray.h | 6 ++ src/db/db/dbLayoutUtils.cc | 199 ++++++++++++++++++++++++++++++++----- src/db/db/dbTrans.h | 46 ++++++++- 3 files changed, 224 insertions(+), 27 deletions(-) diff --git a/src/db/db/dbArray.h b/src/db/db/dbArray.h index 531f11010..44f9b2b67 100644 --- a/src/db/db/dbArray.h +++ b/src/db/db/dbArray.h @@ -2676,6 +2676,12 @@ private: template void transform_delegate (const T &tr, db::ArrayRepository *array_rep) { + // No need to do anything if there are no vector-transforming components as displacement + // is entirely handled outside the delegate + if (tr.is_unity_for_vector ()) { + return; + } + // transform the delegate if (! array_rep && ! mp_base->in_repository) { diff --git a/src/db/db/dbLayoutUtils.cc b/src/db/db/dbLayoutUtils.cc index 3f18ff33a..23a5d33a2 100644 --- a/src/db/db/dbLayoutUtils.cc +++ b/src/db/db/dbLayoutUtils.cc @@ -25,6 +25,7 @@ #include "dbCellVariants.h" #include "dbPolygonTools.h" #include "tlProgress.h" +#include "tlTimer.h" namespace db { @@ -436,9 +437,45 @@ ContextCache::find_layout_context (db::cell_index_type from, db::cell_index_type // ------------------------------------------------------------ // Scale and snap a layout +static bool +is_on_grid (const db::Vector &v, db::Coord g, db::Coord m, db::Coord d) +{ + int64_t dg = int64_t (g) * int64_t (d); + return (int64_t (v.x ()) * m) % dg == 0 && (int64_t (v.y ()) * m) % dg == 0; +} + +static void +scale_and_snap_cell_instance (db::CellInstArray &ci, const db::ICplxTrans &tr, const db::ICplxTrans &trinv, const db::Vector &delta, db::Coord g, db::Coord m, db::Coord d) +{ + db::Trans ti (ci.front ()); + + db::Vector ti_disp = ti.disp (); + ti_disp.transform (tr); + ti_disp = scaled_and_snapped_vector (ti_disp, g, m, d, delta.x (), g, m, d, delta.y ()); + ti_disp.transform (trinv); + + ci.move (ti_disp - ti.disp ()); +} + +static db::Edge +scaled_and_snapped_edge (const db::Edge &e, db::Coord g, db::Coord m, db::Coord d, db::Coord ox, db::Coord oy) +{ + int64_t dg = int64_t (g) * int64_t (d); + + int64_t x1 = snap_to_grid (int64_t (e.p1 ().x ()) * m + int64_t (ox), dg) / int64_t (d); + int64_t y1 = snap_to_grid (int64_t (e.p1 ().y ()) * m + int64_t (oy), dg) / int64_t (d); + + int64_t x2 = snap_to_grid (int64_t (e.p2 ().x ()) * m + int64_t (ox), dg) / int64_t (d); + int64_t y2 = snap_to_grid (int64_t (e.p2 ().y ()) * m + int64_t (oy), dg) / int64_t (d); + + return db::Edge (db::Point (x1, y1), db::Point (x2, y2)); +} + void scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db::Coord d) { + tl::SelfTimer timer (tl::verbosity () >= 31, tl::to_string (tr ("scale_and_snap"))); + if (g < 0) { throw tl::Exception (tl::to_string (tr ("Snapping requires a positive grid value"))); } @@ -453,8 +490,11 @@ scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db db::cell_variants_collector vars (db::ScaleAndGridReducer (g, m, d)); - vars.collect (layout, cell); - vars.separate_variants (layout, cell); + { + tl::SelfTimer timer1 (tl::verbosity () >= 41, tl::to_string (tr ("scale_and_snap: variant formation"))); + vars.collect (layout, cell); + vars.separate_variants (layout, cell); + } std::set called_cells; cell.collect_called_cells (called_cells); @@ -463,9 +503,13 @@ scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db db::LayoutLocker layout_locker (&layout); layout.update (); - std::vector heap; + tl::SelfTimer timer2 (tl::verbosity () >= 41, tl::to_string (tr ("scale_and_snap: snapping and scaling"))); - unsigned int work_layer = layout.insert_layer (); + std::vector heap; + std::vector iterated_array_vectors; + std::vector new_insts_with_props; + std::vector new_insts; + std::vector instances_to_replace; for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { @@ -486,7 +530,8 @@ scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db for (db::Layout::layer_iterator l = layout.begin_layers (); l != layout.end_layers (); ++l) { db::Shapes &s = c->shapes ((*l).first); - db::Shapes &out = c->shapes (work_layer); + + // TODO: properties, edges, edge pairs for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Polygons | db::ShapeIterator::Paths | db::ShapeIterator::Boxes); ! si.at_end (); ++si) { @@ -495,7 +540,8 @@ scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db poly.transform (tr); poly = scaled_and_snapped_polygon (poly, g, m, d, tr_disp.x (), g, m, d, tr_disp.y (), heap); poly.transform (trinv); - out.insert (poly); + + s.replace (*si, poly); } @@ -506,12 +552,35 @@ scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db text.transform (tr); text.trans (db::Trans (text.trans ().rot (), scaled_and_snapped_vector (text.trans ().disp (), g, m, d, tr_disp.x (), g, m, d, tr_disp.y ()))); text.transform (trinv); - out.insert (text); + + s.replace (*si, text); } - s.swap (out); - out.clear (); + for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Edges); ! si.at_end (); ++si) { + + db::Edge edge; + si->edge (edge); + edge.transform (tr); + edge = scaled_and_snapped_edge (edge, g, m , d, tr_disp.x (), tr_disp.y ()); + edge.transform (trinv); + + s.replace (*si, edge); + + } + + for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::EdgePairs); ! si.at_end (); ++si) { + + db::EdgePair edge_pair; + si->edge_pair (edge_pair); + edge_pair.transform (tr); + edge_pair = db::EdgePair (scaled_and_snapped_edge (edge_pair.first (), g, m , d, tr_disp.x (), tr_disp.y ()), + scaled_and_snapped_edge (edge_pair.second (), g, m , d, tr_disp.x (), tr_disp.y ())); + edge_pair.transform (trinv); + + s.replace (*si, edge_pair); + + } } @@ -520,33 +589,115 @@ scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db // as a variant cell (an effect of ScaleAndGridReducer::want_variants(cell) == true where cells have children). // Variant cells are not copied blindly back to the original layout. - std::list new_insts; + new_insts.clear (); + new_insts_with_props.clear (); + instances_to_replace.clear (); for (db::Cell::const_iterator inst = c->begin (); ! inst.at_end (); ++inst) { const db::CellInstArray &ia = inst->cell_inst (); - for (db::CellInstArray::iterator i = ia.begin (); ! i.at_end (); ++i) { - db::Trans ti (*i); - db::Vector ti_disp = ti.disp (); - ti_disp.transform (tr); - ti_disp = scaled_and_snapped_vector (ti_disp, g, m, d, tr_disp.x (), g, m, d, tr_disp.y ()); - ti_disp.transform (trinv); - ti.disp (ti_disp); + // shortcut if we do not need to explode the array + + iterated_array_vectors.clear (); + db::Vector a, b; + unsigned long na, nb; + + bool need_explode = false; + db::CellInstArray new_array (ia); + + if (tr.is_complex ()) { + + need_explode = ia.size () > 1; + + } else if (ia.is_iterated_array (&iterated_array_vectors)) { + + for (std::vector::const_iterator i = iterated_array_vectors.begin (); ! need_explode && i != iterated_array_vectors.end (); ++i) { + need_explode = ! is_on_grid (*i, g, m, d); + } + + if (! need_explode) { + + bool needs_update = false; + for (std::vector::iterator i = iterated_array_vectors.begin (); ! need_explode && i != iterated_array_vectors.end (); ++i) { + db::Vector v = scaled_and_snapped_vector (*i, g, m, d, tr_disp.x (), g, m, d, tr_disp.y ()); + if (v != *i) { + needs_update = true; + *i = v; + } + } + + if (needs_update) { + if (ia.is_complex ()) { + new_array = db::CellInstArray (ia.object (), ia.complex_trans (ia.front ()), iterated_array_vectors.begin (), iterated_array_vectors.end ()); + } else { + new_array = db::CellInstArray (ia.object (), ia.front (), iterated_array_vectors.begin (), iterated_array_vectors.end ()); + } + } + + } + + } else if (ia.is_regular_array (a, b, na, nb)) { + + need_explode = (na > 1 && ! is_on_grid (a, g, m, d)) && (nb > 1 && ! is_on_grid (b, g, m, d)); + + if (! need_explode) { + + a = scaled_and_snapped_vector (a, g, m, d, tr_disp.x (), g, m, d, tr_disp.y ()); + b = scaled_and_snapped_vector (b, g, m, d, tr_disp.x (), g, m, d, tr_disp.y ()); + + if (ia.is_complex ()) { + new_array = db::CellInstArray (ia.object (), ia.complex_trans (ia.front ()), a, b, na, nb); + } else { + new_array = db::CellInstArray (ia.object (), ia.front (), a, b, na, nb); + } + + } + + } + + if (! need_explode) { + + scale_and_snap_cell_instance (new_array, tr, trinv, tr_disp, g, m, d); + c->replace (*inst, new_array); + + } else { + + instances_to_replace.push_back (*inst); + + for (db::CellInstArray::iterator i = ia.begin (); ! i.at_end (); ++i) { + + db::Trans ti (*i); + db::Vector ti_disp = ti.disp (); + ti_disp.transform (tr); + ti_disp = scaled_and_snapped_vector (ti_disp, g, m, d, tr_disp.x (), g, m, d, tr_disp.y ()); + ti_disp.transform (trinv); + ti.disp (ti_disp); + + db::CellInstArray new_array; + if (ia.is_complex ()) { + new_array = db::CellInstArray (ia.object (), ia.complex_trans (ti)); + } else { + new_array = db::CellInstArray (ia.object (), ti); + } + + if (inst->prop_id () > 0) { + new_insts_with_props.push_back (db::CellInstArrayWithProperties (new_array, inst->prop_id ())); + } else { + new_insts.push_back (new_array); + } - if (ia.is_complex ()) { - new_insts.push_back (db::CellInstArray (ia.object (), ia.complex_trans (ti))); - } else { - new_insts.push_back (db::CellInstArray (ia.object (), ti)); } } } - c->clear_insts (); - - for (std::list::const_iterator i = new_insts.begin (); i != new_insts.end (); ++i) { + c->erase_insts (instances_to_replace); + for (std::vector::const_iterator i = new_insts.begin (); i != new_insts.end (); ++i) { + c->insert (*i); + } + for (std::vector::const_iterator i = new_insts_with_props.begin (); i != new_insts_with_props.end (); ++i) { c->insert (*i); } diff --git a/src/db/db/dbTrans.h b/src/db/db/dbTrans.h index 422f87329..5603b3873 100644 --- a/src/db/db/dbTrans.h +++ b/src/db/db/dbTrans.h @@ -77,6 +77,14 @@ struct default_trans return true; } + /** + * @brief Test, whether this is a unit transformation for vectors - i.e. ignoring displacements + */ + bool is_unity_for_vector () const + { + return true; + } + /** * @brief Orthogonal predicate * @@ -410,6 +418,14 @@ public: return m_f == 0; } + /** + * @brief Test, whether this is a unit transformation for vectors - i.e. ignoring displacements + */ + bool is_unity_for_vector () const + { + return m_f == 0; + } + /** * @brief The standard constructor using angle and mirror flag * @@ -869,6 +885,14 @@ public: return m_u.equal (displacement_type ()); } + /** + * @brief Test, whether this is a unit transformation for vectors - i.e. ignoring displacements + */ + bool is_unity_for_vector () const + { + return true; + } + /** * @brief Inversion * @@ -1311,6 +1335,14 @@ public: return m_u.equal (displacement_type ()) && fixpoint_trans::is_unity (); } + /** + * @brief Test, whether this is a unit transformation for vectors - i.e. ignoring displacements + */ + bool is_unity_for_vector () const + { + return fixpoint_trans::is_unity (); + } + /** * @brief The transformation of a distance * @@ -1874,9 +1906,9 @@ public: } /** - * @brief Test, whether this is a unit transformation + * @brief Test, whether this is a unit transformation for vectors - i.e. ignoring displacements */ - bool is_unity () const + bool is_unity_for_vector () const { if (fabs (m_mag - 1.0) > eps_f ()) { return false; @@ -1887,7 +1919,15 @@ public: if (fabs (m_cos - 1.0) > eps_f ()) { return false; } - return disp ().equal (displacement_type ()); + return true; + } + + /** + * @brief Test, whether this is a unit transformation + */ + bool is_unity () const + { + return is_unity_for_vector () && disp ().equal (displacement_type ()); } /** From 834dfa661411ebc404d61b202e423438e5c32645 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 18 Feb 2022 14:22:16 +0100 Subject: [PATCH 3/9] Bug fixes, enhancements, tests for snap and scale improvements. --- src/db/db/dbCellVariants.cc | 39 +++++++- src/db/db/dbLayoutDiff.cc | 105 ++++++++++++++++++++ src/db/db/dbLayoutDiff.h | 3 + src/db/db/dbLayoutUtils.cc | 125 +++++------------------ src/db/db/dbTestSupport.cc | 2 +- src/db/db/dbTestSupport.h | 3 +- src/db/unit_tests/dbLayoutUtilsTests.cc | 126 ++++++++++++++++++++++++ testdata/algo/layout_utils_au_sns4.oas | Bin 0 -> 1174 bytes testdata/algo/scale_and_snap4.oas | Bin 0 -> 475 bytes 9 files changed, 300 insertions(+), 103 deletions(-) create mode 100644 testdata/algo/layout_utils_au_sns4.oas create mode 100644 testdata/algo/scale_and_snap4.oas diff --git a/src/db/db/dbCellVariants.cc b/src/db/db/dbCellVariants.cc index 0126a75c3..5f36cc7b7 100644 --- a/src/db/db/dbCellVariants.cc +++ b/src/db/db/dbCellVariants.cc @@ -511,19 +511,52 @@ VariantsCollectorBase::create_var_instances_non_tl_invariant (db::Cell &in_cell, std::map >::const_iterator f = var_table.find (i->object ().cell_index ()); if (f == var_table.end ()) { - in_cell.insert (*i); + in_cell.insert (*i); } else { const std::map &vt = f->second; - for (db::CellInstArray::iterator ia = i->begin (); ! ia.at_end (); ++ia) { + bool need_explode = false; + bool first = true; + db::cell_index_type ci = 0; + + for (db::CellInstArray::iterator ia = i->begin (); ! ia.at_end () && ! need_explode; ++ia) { db::ICplxTrans rt = mp_red->reduce (for_var * mp_red->reduce_trans (i->complex_trans (*ia))); std::map::const_iterator v = vt.find (rt); tl_assert (v != vt.end ()); - in_cell.insert (db::CellInstArrayWithProperties (db::CellInstArray (db::CellInst (v->second), i->complex_trans (*ia)), i->properties_id ())); + if (first) { + ci = v->second; + first = false; + } else { + need_explode = (ci != v->second); + } + + } + + if (need_explode) { + + for (db::CellInstArray::iterator ia = i->begin (); ! ia.at_end (); ++ia) { + + db::ICplxTrans rt = mp_red->reduce (for_var * mp_red->reduce_trans (i->complex_trans (*ia))); + std::map::const_iterator v = vt.find (rt); + tl_assert (v != vt.end ()); + + in_cell.insert (db::CellInstArrayWithProperties (db::CellInstArray (db::CellInst (v->second), i->complex_trans (*ia)), i->properties_id ())); + + } + + } else if (ci != i->object ().cell_index ()) { + + db::CellInstArray new_array = *i; + new_array.object () = db::CellInst (ci); + in_cell.insert (db::CellInstArrayWithProperties (new_array, i->properties_id ())); + + } else { + + in_cell.insert (*i); } diff --git a/src/db/db/dbLayoutDiff.cc b/src/db/db/dbLayoutDiff.cc index e57cd0240..e7940a24b 100644 --- a/src/db/db/dbLayoutDiff.cc +++ b/src/db/db/dbLayoutDiff.cc @@ -287,6 +287,32 @@ private: db::Coord m_tolerance; }; +/** + * @brief A fuzzy compare operator for edge pairs + * Compares two edge pair objects applying a tolerance between them. The tolerance is the allowed deviation + * of points in database units. + */ +struct EdgePairCompareOpWithTolerance +{ + EdgePairCompareOpWithTolerance (db::Coord tolerance) + : m_ec (tolerance) + { } + + bool operator() (const db::EdgePair &a, const db::EdgePair &b) const + { + if (m_ec (a.first (), b.first ())) { + return true; + } else if (m_ec (b.first (), a.first ())) { + return false; + } else { + return m_ec (a.second (), b.second ()); + } + } + +private: + EdgeCompareOpWithTolerance m_ec; +}; + /** * @brief A fuzzy compare operator for boxes * Compares two box objects applying a tolerance between them. The tolerance is the allowed deviation @@ -492,6 +518,12 @@ make_edge_compare_func (db::Coord tolerance) return pair_compare_func > (EdgeCompareOpWithTolerance (tolerance), std_compare_func ()); } +pair_compare_func > +make_edge_pair_compare_func (db::Coord tolerance) +{ + return pair_compare_func > (EdgePairCompareOpWithTolerance (tolerance), std_compare_func ()); +} + pair_compare_func > make_box_compare_func (db::Coord tolerance) { @@ -540,6 +572,21 @@ collect_edges (const db::Layout & /*l*/, const db::Cell *c, unsigned int layer, } } +static void +collect_edge_pairs (const db::Layout & /*l*/, const db::Cell *c, unsigned int layer, unsigned int flags, std::vector< std::pair > &shapes, PropertyMapper &pn) +{ + shapes.clear (); + + for (db::ShapeIterator s = c->shapes (layer).begin (db::ShapeIterator::EdgePairs); !s.at_end (); ++s) { + db::properties_id_type prop_id = 0; + if (! (flags & layout_diff::f_no_properties)) { + prop_id = pn (s->prop_id ()); + } + shapes.push_back (std::make_pair (db::EdgePair (), prop_id)); + s->edge_pair (shapes.back ().first); + } +} + static void collect_boxes (const db::Layout &, const db::Cell *c, unsigned int layer, unsigned int flags, std::vector< std::pair > &shapes, PropertyMapper &pn) { @@ -828,6 +875,8 @@ do_compare_layouts (const db::Layout &a, const db::Cell *top_a, const db::Layout std::vector > boxes_b; std::vector > edges_a; std::vector > edges_b; + std::vector > edge_pairs_a; + std::vector > edge_pairs_b; for (unsigned int cci = 0; cci < common_cells.size (); ++cci) { @@ -1053,6 +1102,31 @@ do_compare_layouts (const db::Layout &a, const db::Cell *top_a, const db::Layout r.end_edge_differences (); } + // compare edge pairs + + edge_pairs_a.clear(); + edge_pairs_b.clear(); + if (is_valid_a) { + collect_edge_pairs (a, cell_a, layer_a, flags, edge_pairs_a, prop_normalize_a); + } + if (is_valid_b) { + collect_edge_pairs (b, cell_b, layer_b, flags, edge_pairs_b, prop_normalize_b); + } + + reduce (edge_pairs_a, edge_pairs_b, make_edge_pair_compare_func (tolerance), tolerance > 0); + + if (!edge_pairs_a.empty () || !edge_pairs_b.empty ()) { + differs = true; + if (flags & layout_diff::f_silent) { + return false; + } + r.begin_edge_pair_differences (); + if (verbose) { + r.detailed_diff (n.properties_repository (), edge_pairs_a, edge_pairs_b); + } + r.end_edge_pair_differences (); + } + r.end_layer (); } @@ -1130,6 +1204,9 @@ public: void begin_edge_differences (); void detailed_diff (const db::PropertiesRepository &pr, const std::vector > &a, const std::vector > &b); void end_edge_differences (); + void begin_edge_pair_differences (); + void detailed_diff (const db::PropertiesRepository &pr, const std::vector > &a, const std::vector > &b); + void end_edge_pair_differences (); void begin_text_differences (); void detailed_diff (const db::PropertiesRepository &pr, const std::vector > &a, const std::vector > &b); void end_text_differences (); @@ -1525,6 +1602,34 @@ PrintingDifferenceReceiver::end_edge_differences () { } +void +PrintingDifferenceReceiver::begin_edge_pair_differences () +{ + try { + enough (tl::error) << "Edge pairs differ for layer " << m_layer.to_string () << " in cell " << m_cellname; + } catch (tl::CancelException &) { + // ignore cancel exceptions + } +} + +void +PrintingDifferenceReceiver::detailed_diff (const db::PropertiesRepository &pr, const std::vector > &a, const std::vector > &b) +{ + try { + enough (tl::info) << "Not in b but in a:"; + print_diffs (pr, a, b); + enough (tl::info) << "Not in a but in b:"; + print_diffs (pr, b, a); + } catch (tl::CancelException &) { + // ignore cancel exceptions + } +} + +void +PrintingDifferenceReceiver::end_edge_pair_differences () +{ +} + void PrintingDifferenceReceiver::begin_text_differences () { diff --git a/src/db/db/dbLayoutDiff.h b/src/db/db/dbLayoutDiff.h index ed0e01e0b..4482c5009 100644 --- a/src/db/db/dbLayoutDiff.h +++ b/src/db/db/dbLayoutDiff.h @@ -119,6 +119,9 @@ public: virtual void begin_edge_differences () { } virtual void detailed_diff (const db::PropertiesRepository & /*pr*/, const std::vector > & /*a*/, const std::vector > & /*b*/) { } virtual void end_edge_differences () { } + virtual void begin_edge_pair_differences () { } + virtual void detailed_diff (const db::PropertiesRepository & /*pr*/, const std::vector > & /*a*/, const std::vector > & /*b*/) { } + virtual void end_edge_pair_differences () { } virtual void begin_text_differences () { } virtual void detailed_diff (const db::PropertiesRepository & /*pr*/, const std::vector > & /*a*/, const std::vector > & /*b*/) { } virtual void end_text_differences () { } diff --git a/src/db/db/dbLayoutUtils.cc b/src/db/db/dbLayoutUtils.cc index 23a5d33a2..2196f9fa4 100644 --- a/src/db/db/dbLayoutUtils.cc +++ b/src/db/db/dbLayoutUtils.cc @@ -507,9 +507,6 @@ scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db std::vector heap; std::vector iterated_array_vectors; - std::vector new_insts_with_props; - std::vector new_insts; - std::vector instances_to_replace; for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { @@ -530,8 +527,7 @@ scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db for (db::Layout::layer_iterator l = layout.begin_layers (); l != layout.end_layers (); ++l) { db::Shapes &s = c->shapes ((*l).first); - - // TODO: properties, edges, edge pairs + db::Shapes new_shapes; for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Polygons | db::ShapeIterator::Paths | db::ShapeIterator::Boxes); ! si.at_end (); ++si) { @@ -541,7 +537,11 @@ scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db poly = scaled_and_snapped_polygon (poly, g, m, d, tr_disp.x (), g, m, d, tr_disp.y (), heap); poly.transform (trinv); - s.replace (*si, poly); + if (si->is_box () && poly.is_box ()) { + new_shapes.insert (db::BoxWithProperties (poly.box (), si->prop_id ())); + } else { + new_shapes.insert (db::PolygonWithProperties (poly, si->prop_id ())); + } } @@ -553,7 +553,7 @@ scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db text.trans (db::Trans (text.trans ().rot (), scaled_and_snapped_vector (text.trans ().disp (), g, m, d, tr_disp.x (), g, m, d, tr_disp.y ()))); text.transform (trinv); - s.replace (*si, text); + new_shapes.insert (db::TextWithProperties (text, si->prop_id ())); } @@ -565,7 +565,7 @@ scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db edge = scaled_and_snapped_edge (edge, g, m , d, tr_disp.x (), tr_disp.y ()); edge.transform (trinv); - s.replace (*si, edge); + new_shapes.insert (db::EdgeWithProperties (edge, si->prop_id ())); } @@ -578,127 +578,56 @@ scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db scaled_and_snapped_edge (edge_pair.second (), g, m , d, tr_disp.x (), tr_disp.y ())); edge_pair.transform (trinv); - s.replace (*si, edge_pair); + new_shapes.insert (db::EdgePairWithProperties (edge_pair, si->prop_id ())); } + s.swap (new_shapes); + } // Snap instance placements to grid and magnify // NOTE: we can modify the instances because the ScaleAndGridReducer marked every cell with children // as a variant cell (an effect of ScaleAndGridReducer::want_variants(cell) == true where cells have children). - // Variant cells are not copied blindly back to the original layout. - - new_insts.clear (); - new_insts_with_props.clear (); - instances_to_replace.clear (); + // The variant formation also made sure the iterated and regular arrays are exploded where required. for (db::Cell::const_iterator inst = c->begin (); ! inst.at_end (); ++inst) { const db::CellInstArray &ia = inst->cell_inst (); - // shortcut if we do not need to explode the array - iterated_array_vectors.clear (); db::Vector a, b; unsigned long na, nb; - bool need_explode = false; db::CellInstArray new_array (ia); - if (tr.is_complex ()) { + if (ia.is_iterated_array (&iterated_array_vectors)) { - need_explode = ia.size () > 1; - - } else if (ia.is_iterated_array (&iterated_array_vectors)) { - - for (std::vector::const_iterator i = iterated_array_vectors.begin (); ! need_explode && i != iterated_array_vectors.end (); ++i) { - need_explode = ! is_on_grid (*i, g, m, d); + bool needs_update = false; + for (std::vector::iterator i = iterated_array_vectors.begin (); i != iterated_array_vectors.end (); ++i) { + db::Vector v = scaled_and_snapped_vector (*i, g, m, d, tr_disp.x (), g, m, d, tr_disp.y ()); + if (v != *i) { + needs_update = true; + *i = v; + } } - if (! need_explode) { - - bool needs_update = false; - for (std::vector::iterator i = iterated_array_vectors.begin (); ! need_explode && i != iterated_array_vectors.end (); ++i) { - db::Vector v = scaled_and_snapped_vector (*i, g, m, d, tr_disp.x (), g, m, d, tr_disp.y ()); - if (v != *i) { - needs_update = true; - *i = v; - } - } - - if (needs_update) { - if (ia.is_complex ()) { - new_array = db::CellInstArray (ia.object (), ia.complex_trans (ia.front ()), iterated_array_vectors.begin (), iterated_array_vectors.end ()); - } else { - new_array = db::CellInstArray (ia.object (), ia.front (), iterated_array_vectors.begin (), iterated_array_vectors.end ()); - } - } - + if (needs_update) { + new_array = db::CellInstArray (ia.object (), ia.complex_trans (ia.front ()), iterated_array_vectors.begin (), iterated_array_vectors.end ()); } } else if (ia.is_regular_array (a, b, na, nb)) { - need_explode = (na > 1 && ! is_on_grid (a, g, m, d)) && (nb > 1 && ! is_on_grid (b, g, m, d)); + a = scaled_and_snapped_vector (a, g, m, d, tr_disp.x (), g, m, d, tr_disp.y ()); + b = scaled_and_snapped_vector (b, g, m, d, tr_disp.x (), g, m, d, tr_disp.y ()); - if (! need_explode) { - - a = scaled_and_snapped_vector (a, g, m, d, tr_disp.x (), g, m, d, tr_disp.y ()); - b = scaled_and_snapped_vector (b, g, m, d, tr_disp.x (), g, m, d, tr_disp.y ()); - - if (ia.is_complex ()) { - new_array = db::CellInstArray (ia.object (), ia.complex_trans (ia.front ()), a, b, na, nb); - } else { - new_array = db::CellInstArray (ia.object (), ia.front (), a, b, na, nb); - } - - } + new_array = db::CellInstArray (ia.object (), ia.complex_trans (ia.front ()), a, b, na, nb); } - if (! need_explode) { + scale_and_snap_cell_instance (new_array, tr, trinv, tr_disp, g, m, d); + c->replace (*inst, new_array); - scale_and_snap_cell_instance (new_array, tr, trinv, tr_disp, g, m, d); - c->replace (*inst, new_array); - - } else { - - instances_to_replace.push_back (*inst); - - for (db::CellInstArray::iterator i = ia.begin (); ! i.at_end (); ++i) { - - db::Trans ti (*i); - db::Vector ti_disp = ti.disp (); - ti_disp.transform (tr); - ti_disp = scaled_and_snapped_vector (ti_disp, g, m, d, tr_disp.x (), g, m, d, tr_disp.y ()); - ti_disp.transform (trinv); - ti.disp (ti_disp); - - db::CellInstArray new_array; - if (ia.is_complex ()) { - new_array = db::CellInstArray (ia.object (), ia.complex_trans (ti)); - } else { - new_array = db::CellInstArray (ia.object (), ti); - } - - if (inst->prop_id () > 0) { - new_insts_with_props.push_back (db::CellInstArrayWithProperties (new_array, inst->prop_id ())); - } else { - new_insts.push_back (new_array); - } - - } - - } - - } - - c->erase_insts (instances_to_replace); - for (std::vector::const_iterator i = new_insts.begin (); i != new_insts.end (); ++i) { - c->insert (*i); - } - for (std::vector::const_iterator i = new_insts_with_props.begin (); i != new_insts_with_props.end (); ++i) { - c->insert (*i); } } diff --git a/src/db/db/dbTestSupport.cc b/src/db/db/dbTestSupport.cc index aa5522df0..090e849a2 100644 --- a/src/db/db/dbTestSupport.cc +++ b/src/db/db/dbTestSupport.cc @@ -138,7 +138,7 @@ void compare_layouts (tl::TestBase *_this, const db::Layout &layout, const std:: equal = db::compare_layouts (*subject, layout_au, (n > 0 ? db::layout_diff::f_silent : db::layout_diff::f_verbose) | ((norm & AsPolygons) != 0 ? db::layout_diff::f_boxes_as_polygons + db::layout_diff::f_paths_as_polygons : 0) - | db::layout_diff::f_flatten_array_insts + | ((norm & WithArrays) != 0 ? 0 : db::layout_diff::f_flatten_array_insts) /*| db::layout_diff::f_no_text_details | db::layout_diff::f_no_text_orientation*/ , tolerance, 100 /*max diff lines*/); if (equal && n > 0) { diff --git a/src/db/db/dbTestSupport.h b/src/db/db/dbTestSupport.h index 9b031fdce..8f89cf7e9 100644 --- a/src/db/db/dbTestSupport.h +++ b/src/db/db/dbTestSupport.h @@ -56,7 +56,8 @@ enum NormalizationMode WriteOAS = 2, // normalize subject by writing to OASIS and reading back NormFileMask = 7, // bits the extract for file mode NoContext = 8, // write tmp file without context - AsPolygons = 16 // paths and boxes are treated as polygons + AsPolygons = 16, // paths and boxes are treated as polygons + WithArrays = 32 // do not flatten arrays }; /** diff --git a/src/db/unit_tests/dbLayoutUtilsTests.cc b/src/db/unit_tests/dbLayoutUtilsTests.cc index 3dac06878..26130e050 100644 --- a/src/db/unit_tests/dbLayoutUtilsTests.cc +++ b/src/db/unit_tests/dbLayoutUtilsTests.cc @@ -25,6 +25,8 @@ #include "dbCellMapping.h" #include "dbTestSupport.h" #include "dbReader.h" +#include "dbLayoutDiff.h" +#include "dbPropertiesRepository.h" #include "tlString.h" #include "tlUnitTest.h" @@ -653,3 +655,127 @@ TEST(18_scale_and_snap) CHECKPOINT(); db::compare_layouts (_this, l1, tl::testdata () + "/algo/layout_utils_au_sns3.gds"); } + +TEST(19_scale_and_snap_basic) +{ + db::Layout l1; + db::Layout l2; + + db::PropertiesRepository::properties_set ps1; + ps1.insert (std::make_pair (l1.properties_repository ().prop_name_id (tl::Variant ("p")), tl::Variant (17))); + db::properties_id_type pid1 = l1.properties_repository ().properties_id (ps1); + + db::PropertiesRepository::properties_set ps2; + ps2.insert (std::make_pair (l2.properties_repository ().prop_name_id (tl::Variant ("p")), tl::Variant (17))); + db::properties_id_type pid2 = l2.properties_repository ().properties_id (ps2); + + db::Cell &top1 = l1.cell (l1.add_cell ("TOP")); + db::Cell &top2 = l2.cell (l2.add_cell ("TOP")); + + db::Cell &a1 = l1.cell (l1.add_cell ("A")); + db::Cell &a2a = l2.cell (l2.add_cell ("A")); + + unsigned int layer1 = l1.insert_layer (db::LayerProperties (1, 0)); + unsigned int layer2 = l2.insert_layer (db::LayerProperties (1, 0)); + + a1.shapes (layer1).insert (db::Box (0, 0, 100, 100)); + a2a.shapes (layer2).insert (db::Box (0, 0, 100, 100)); + + top1.shapes (layer1).insert (db::Box (11, 21, 31, 41)); + top2.shapes (layer2).insert (db::Box (10, 20, 30, 40)); + + top1.shapes (layer1).insert (db::BoxWithProperties (db::Box (11, 21, 31, 41), pid1)); + top2.shapes (layer2).insert (db::BoxWithProperties (db::Box (10, 20, 30, 40), pid2)); + + top1.shapes (layer1).insert (db::Edge (11, 21, 31, 41)); + top2.shapes (layer2).insert (db::Edge (10, 20, 30, 40)); + + top1.shapes (layer1).insert (db::EdgeWithProperties (db::Edge (11, 21, 31, 41), pid1)); + top2.shapes (layer2).insert (db::EdgeWithProperties (db::Edge (10, 20, 30, 40), pid2)); + + top1.shapes (layer1).insert (db::EdgePair (db::Edge (11, 21, 31, 41), db::Edge (111, 121, 131, 141))); + top2.shapes (layer2).insert (db::EdgePair (db::Edge (10, 20, 30, 40), db::Edge (110, 120, 130, 140))); + + top1.shapes (layer1).insert (db::EdgePairWithProperties (db::EdgePair (db::Edge (11, 21, 31, 41), db::Edge (111, 121, 131, 141)), pid1)); + top2.shapes (layer2).insert (db::EdgePairWithProperties (db::EdgePair (db::Edge (10, 20, 30, 40), db::Edge (110, 120, 130, 140)), pid2)); + + top1.shapes (layer1).insert (db::Polygon (db::Box (11, 21, 31, 41))); + top2.shapes (layer2).insert (db::Polygon (db::Box (10, 20, 30, 40))); + + top1.shapes (layer1).insert (db::PolygonWithProperties (db::Polygon (db::Box (11, 21, 31, 41)), pid1)); + top2.shapes (layer2).insert (db::PolygonWithProperties (db::Polygon (db::Box (10, 20, 30, 40)), pid2)); + + db::Point pts1[] = { + db::Point (1, 101), + db::Point (101, 101), + db::Point (101, 201) + }; + + db::Point pts2[] = { + db::Point (0, 100), + db::Point (100, 100), + db::Point (100, 200) + }; + + top1.shapes (layer1).insert (db::Path (&pts1 [0], &pts1 [sizeof (pts1) / sizeof(pts1 [0])], 20)); + top2.shapes (layer2).insert (db::Path (&pts2 [0], &pts2 [sizeof (pts2) / sizeof(pts2 [0])], 20)); + + top1.shapes (layer1).insert (db::PathWithProperties (db::Path (&pts1 [0], &pts1 [sizeof (pts1) / sizeof(pts1 [0])], 20), pid1)); + top2.shapes (layer2).insert (db::PathWithProperties (db::Path (&pts2 [0], &pts2 [sizeof (pts2) / sizeof(pts2 [0])], 20), pid2)); + + top1.shapes (layer1).insert (db::Text ("t1", db::Trans (db::Vector (11, 21)))); + top2.shapes (layer2).insert (db::Text ("t1", db::Trans (db::Vector (10, 20)))); + + top1.shapes (layer1).insert (db::TextWithProperties (db::Text ("t1", db::Trans (db::Vector (11, 21))), pid1)); + top2.shapes (layer2).insert (db::TextWithProperties (db::Text ("t1", db::Trans (db::Vector (10, 20))), pid2)); + + top1.insert (db::CellInstArray (db::CellInst (a1.cell_index ()), db::Trans (db::Vector (11, 21)))); + top2.insert (db::CellInstArray (db::CellInst (a2a.cell_index ()), db::Trans (db::Vector (10, 20)))); + + top1.insert (db::CellInstArrayWithProperties (db::CellInstArray (db::CellInst (a1.cell_index ()), db::Trans (db::Vector (11, 21))), pid1)); + top2.insert (db::CellInstArrayWithProperties (db::CellInstArray (db::CellInst (a2a.cell_index ()), db::Trans (db::Vector (10, 20))), pid2)); + + top1.insert (db::CellInstArray (db::CellInst (a1.cell_index ()), db::Trans (db::Vector (11, 21)), db::Vector (0, 10), db::Vector (10, 0), 2, 3)); + top2.insert (db::CellInstArray (db::CellInst (a2a.cell_index ()), db::Trans (db::Vector (10, 20)), db::Vector (0, 10), db::Vector (10, 0), 2, 3)); + + top1.insert (db::CellInstArrayWithProperties (db::CellInstArray (db::CellInst (a1.cell_index ()), db::Trans (db::Vector (11, 21)), db::Vector (0, 10), db::Vector (10, 0), 2, 3), pid1)); + top2.insert (db::CellInstArrayWithProperties (db::CellInstArray (db::CellInst (a2a.cell_index ()), db::Trans (db::Vector (10, 20)), db::Vector (0, 10), db::Vector (10, 0), 2, 3), pid2)); + + std::vector ia; + ia.push_back (db::Vector (0, 0)); + ia.push_back (db::Vector (10, 0)); + ia.push_back (db::Vector (0, 10)); + + top1.insert (db::CellInstArray (db::CellInst (a1.cell_index ()), db::Trans (db::Vector (11, 21)), ia.begin (), ia.end ())); + top2.insert (db::CellInstArray (db::CellInst (a2a.cell_index ()), db::Trans (db::Vector (10, 20)), ia.begin (), ia.end ())); + + top1.insert (db::CellInstArrayWithProperties (db::CellInstArray (db::CellInst (a1.cell_index ()), db::Trans (db::Vector (11, 21)), ia.begin (), ia.end ()), pid1)); + top2.insert (db::CellInstArrayWithProperties (db::CellInstArray (db::CellInst (a2a.cell_index ()), db::Trans (db::Vector (10, 20)), ia.begin (), ia.end ()), pid2)); + + db::scale_and_snap (l1, top1, 10, 1, 1); + + bool equal = db::compare_layouts (l1, l2, + db::layout_diff::f_verbose + | db::layout_diff::f_boxes_as_polygons + | db::layout_diff::f_paths_as_polygons + , 0, 100 /*max diff lines*/); + EXPECT_EQ (equal, true); +} + +TEST(20_scale_and_snap) +{ + db::Layout l1; + { + std::string fn (tl::testdata ()); + fn += "/algo/scale_and_snap4.oas"; + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (l1); + } + + db::scale_and_snap (l1, l1.cell (*l1.begin_top_down ()), 10, 95, 100); + + CHECKPOINT(); + db::compare_layouts (_this, l1, tl::testdata () + "/algo/layout_utils_au_sns4.oas", db::NormalizationMode (db::WriteOAS + db::WithArrays)); +} + diff --git a/testdata/algo/layout_utils_au_sns4.oas b/testdata/algo/layout_utils_au_sns4.oas new file mode 100644 index 0000000000000000000000000000000000000000..3213ccba4901ba5331540e81342bcea159a88c1a GIT binary patch literal 1174 zcmd_ozfaU)7zgmaeS6pAdWCyS%fV4N5^!*U(6{_DF)@ua*aQwkPl3gb{s+!FnA||3 ziHrGV_3qlj9~@C zDuy)-*vzq+V>8EQj?EmKIW}`_=Ge@!nPan$&Aw;O*q?}!SIiDL4NieBI0?4F32+>2 zfn%Tp+TbW?fedVdBj7M-f(_6B>);Sr19hM{qu9V7?O)zzp%5Gp`MYOs^2`(+DuroOpfPje*4QVv8+@5 zRA*xJ@IyINlS2dY?S+;R4CduxWH!_@V0gjKfDB|rrGn#q9V6m{J>C6WUE)3cLR{TlgW|(I zT|zuKSY&u*Akv|J*c8Z!as|hS_y@#0yZZR>Fauf4V1m(+mr>*}Bf|nVUIxKGjF%QM zy-?s{Y&W{aa#5p=Pq1RbQRWA+jLgjU*zd6mR&+Sbh+z~GdcppJU9jju><$B=GN>be l*fZ$w&ef- literal 0 HcmV?d00001 From a133a8f43b88634018221ab87920e0a5085d7533 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 18 Feb 2022 18:43:02 +0100 Subject: [PATCH 4/9] Reverted some changes, removed idle code --- src/db/db/dbArray.h | 6 ----- src/db/db/dbLayoutUtils.cc | 7 ------ src/db/db/dbTrans.h | 46 +++----------------------------------- 3 files changed, 3 insertions(+), 56 deletions(-) diff --git a/src/db/db/dbArray.h b/src/db/db/dbArray.h index 44f9b2b67..531f11010 100644 --- a/src/db/db/dbArray.h +++ b/src/db/db/dbArray.h @@ -2676,12 +2676,6 @@ private: template void transform_delegate (const T &tr, db::ArrayRepository *array_rep) { - // No need to do anything if there are no vector-transforming components as displacement - // is entirely handled outside the delegate - if (tr.is_unity_for_vector ()) { - return; - } - // transform the delegate if (! array_rep && ! mp_base->in_repository) { diff --git a/src/db/db/dbLayoutUtils.cc b/src/db/db/dbLayoutUtils.cc index 2196f9fa4..319a878d9 100644 --- a/src/db/db/dbLayoutUtils.cc +++ b/src/db/db/dbLayoutUtils.cc @@ -437,13 +437,6 @@ ContextCache::find_layout_context (db::cell_index_type from, db::cell_index_type // ------------------------------------------------------------ // Scale and snap a layout -static bool -is_on_grid (const db::Vector &v, db::Coord g, db::Coord m, db::Coord d) -{ - int64_t dg = int64_t (g) * int64_t (d); - return (int64_t (v.x ()) * m) % dg == 0 && (int64_t (v.y ()) * m) % dg == 0; -} - static void scale_and_snap_cell_instance (db::CellInstArray &ci, const db::ICplxTrans &tr, const db::ICplxTrans &trinv, const db::Vector &delta, db::Coord g, db::Coord m, db::Coord d) { diff --git a/src/db/db/dbTrans.h b/src/db/db/dbTrans.h index 5603b3873..422f87329 100644 --- a/src/db/db/dbTrans.h +++ b/src/db/db/dbTrans.h @@ -77,14 +77,6 @@ struct default_trans return true; } - /** - * @brief Test, whether this is a unit transformation for vectors - i.e. ignoring displacements - */ - bool is_unity_for_vector () const - { - return true; - } - /** * @brief Orthogonal predicate * @@ -418,14 +410,6 @@ public: return m_f == 0; } - /** - * @brief Test, whether this is a unit transformation for vectors - i.e. ignoring displacements - */ - bool is_unity_for_vector () const - { - return m_f == 0; - } - /** * @brief The standard constructor using angle and mirror flag * @@ -885,14 +869,6 @@ public: return m_u.equal (displacement_type ()); } - /** - * @brief Test, whether this is a unit transformation for vectors - i.e. ignoring displacements - */ - bool is_unity_for_vector () const - { - return true; - } - /** * @brief Inversion * @@ -1335,14 +1311,6 @@ public: return m_u.equal (displacement_type ()) && fixpoint_trans::is_unity (); } - /** - * @brief Test, whether this is a unit transformation for vectors - i.e. ignoring displacements - */ - bool is_unity_for_vector () const - { - return fixpoint_trans::is_unity (); - } - /** * @brief The transformation of a distance * @@ -1906,9 +1874,9 @@ public: } /** - * @brief Test, whether this is a unit transformation for vectors - i.e. ignoring displacements + * @brief Test, whether this is a unit transformation */ - bool is_unity_for_vector () const + bool is_unity () const { if (fabs (m_mag - 1.0) > eps_f ()) { return false; @@ -1919,15 +1887,7 @@ public: if (fabs (m_cos - 1.0) > eps_f ()) { return false; } - return true; - } - - /** - * @brief Test, whether this is a unit transformation - */ - bool is_unity () const - { - return is_unity_for_vector () && disp ().equal (displacement_type ()); + return disp ().equal (displacement_type ()); } /** From c5da9c717d6ce9c5197b973462f6289ba43ef6a8 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 18 Feb 2022 18:49:00 +0100 Subject: [PATCH 5/9] scale_and_snap: separate handling of shapes with properties and without --- src/db/db/dbLayoutUtils.cc | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/src/db/db/dbLayoutUtils.cc b/src/db/db/dbLayoutUtils.cc index 319a878d9..82ead48ce 100644 --- a/src/db/db/dbLayoutUtils.cc +++ b/src/db/db/dbLayoutUtils.cc @@ -531,9 +531,17 @@ scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db poly.transform (trinv); if (si->is_box () && poly.is_box ()) { - new_shapes.insert (db::BoxWithProperties (poly.box (), si->prop_id ())); + if (si->has_prop_id ()) { + new_shapes.insert (db::BoxWithProperties (poly.box (), si->prop_id ())); + } else { + new_shapes.insert (poly.box ()); + } } else { - new_shapes.insert (db::PolygonWithProperties (poly, si->prop_id ())); + if (si->has_prop_id ()) { + new_shapes.insert (db::PolygonWithProperties (poly, si->prop_id ())); + } else { + new_shapes.insert (poly); + } } } @@ -546,7 +554,11 @@ scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db text.trans (db::Trans (text.trans ().rot (), scaled_and_snapped_vector (text.trans ().disp (), g, m, d, tr_disp.x (), g, m, d, tr_disp.y ()))); text.transform (trinv); - new_shapes.insert (db::TextWithProperties (text, si->prop_id ())); + if (si->has_prop_id ()) { + new_shapes.insert (db::TextWithProperties (text, si->prop_id ())); + } else { + new_shapes.insert (text); + } } @@ -558,7 +570,11 @@ scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db edge = scaled_and_snapped_edge (edge, g, m , d, tr_disp.x (), tr_disp.y ()); edge.transform (trinv); - new_shapes.insert (db::EdgeWithProperties (edge, si->prop_id ())); + if (si->has_prop_id ()) { + new_shapes.insert (db::EdgeWithProperties (edge, si->prop_id ())); + } else { + new_shapes.insert (edge); + } } @@ -571,7 +587,11 @@ scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db scaled_and_snapped_edge (edge_pair.second (), g, m , d, tr_disp.x (), tr_disp.y ())); edge_pair.transform (trinv); - new_shapes.insert (db::EdgePairWithProperties (edge_pair, si->prop_id ())); + if (si->has_prop_id ()) { + new_shapes.insert (db::EdgePairWithProperties (edge_pair, si->prop_id ())); + } else { + new_shapes.insert (edge_pair); + } } From 30f774f0555013a4bc281091e9bde4135b43c0a1 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 19 Feb 2022 17:57:41 +0100 Subject: [PATCH 6/9] WIP: dynamic definition of macro categories (currently: drc, lvs) --- .../drc/built-in-macros/drc_interpreters.lym | 5 ++ src/lay/lay/gsiDeclLayApplication.cc | 12 +++++ src/lay/lay/layApplication.cc | 43 +++++++++++++++- src/lay/lay/layApplication.h | 7 +++ src/lay/lay/layMacroController.cc | 51 +++---------------- src/lay/lay/layMacroController.h | 8 ++- .../lvs/built-in-macros/lvs_interpreters.lym | 5 ++ src/lym/lym/lymMacro.cc | 46 +++++++++++++---- src/lym/lym/lymMacro.h | 12 ++++- 9 files changed, 132 insertions(+), 57 deletions(-) diff --git a/src/drc/drc/built-in-macros/drc_interpreters.lym b/src/drc/drc/built-in-macros/drc_interpreters.lym index 4a0108d44..a5c4d13ed 100644 --- a/src/drc/drc/built-in-macros/drc_interpreters.lym +++ b/src/drc/drc/built-in-macros/drc_interpreters.lym @@ -158,6 +158,11 @@ module DRC # Register the new interpreters DRCInterpreter::new(drc_recipe) DRCPlainTextInterpreter::new(drc_recipe) + + # Creates a new macro category + if RBA::Application::instance + RBA::Application::instance.add_macro_category("drc", "DRC", [ "drc" ]) + end end diff --git a/src/lay/lay/gsiDeclLayApplication.cc b/src/lay/lay/gsiDeclLayApplication.cc index 287b80f92..fbf23517b 100644 --- a/src/lay/lay/gsiDeclLayApplication.cc +++ b/src/lay/lay/gsiDeclLayApplication.cc @@ -87,6 +87,12 @@ static std::string version (C *) return C::version (); } +template +static void add_macro_category (C *c, const std::string &name, const std::string &description, const std::vector &folders) +{ + c->add_macro_category (name, description, folders); +} + template static gsi::Methods application_methods () { @@ -226,6 +232,12 @@ static gsi::Methods application_methods () "@brief Returns the architecture string\n" "This method has been introduced in version 0.25." ) + + method_ext &> ("add_macro_category", &add_macro_category, gsi::arg ("name"), gsi::arg ("description"), gsi::arg ("folders"), + "@brief Creates a new macro category\n" + "Creating a new macro category is only possible during the autorun_early stage. " + "The new macro category must correspond to an interpreter registered at the same stage.\n" + "This method has been introduced in version 0.28." + ) + method ("instance", &C::instance, "@brief Return the singleton instance of the application\n" "\n" diff --git a/src/lay/lay/layApplication.cc b/src/lay/lay/layApplication.cc index f5d4dd505..a66c633a2 100644 --- a/src/lay/lay/layApplication.cc +++ b/src/lay/lay/layApplication.cc @@ -686,6 +686,22 @@ ApplicationBase::init_app () if (mc) { + // create the basic macro categories + + if (ruby_interpreter ().available ()) { + std::vector folders; + folders.push_back ("macros"); + folders.push_back ("ruby"); + mc->add_macro_category ("macros", "Ruby", folders); + } + + if (python_interpreter ().available ()) { + std::vector folders; + folders.push_back ("pymacros"); + folders.push_back ("python"); + mc->add_macro_category ("pymacros", "Python", folders); + } + mc->enable_implicit_macros (! m_no_macros); // Add the global ruby modules as the first ones. @@ -741,13 +757,29 @@ ApplicationBase::init_app () } } + std::set already_executed; + // run all early autorun macros - lym::MacroCollection::root ().autorun_early (); + lym::MacroCollection::root ().autorun_early (&already_executed); + + // autorun_early may have added macro categories, so we need to call finish() again + if (mc) { + + mc->finish (); + + // as this regenerates the macro collection, autorun_early is required again + // note: this does no re-execute macros that have been executed already + lym::MacroCollection::root ().autorun_early (&already_executed); + + } // rescan the folders because early autorun macros might have added // suffixes through the MacroInterpreter interface. lym::MacroCollection::root ().rescan (); + // and yet another autorun_early pass .. + lym::MacroCollection::root ().autorun_early (&already_executed); + // creates the main window or plugin root as required setup (); @@ -785,6 +817,15 @@ ApplicationBase::init_app () } } +void +ApplicationBase::add_macro_category (const std::string &name, const std::string &description, const std::vector &folders) +{ + lay::MacroController *mc = lay::MacroController::instance (); + if (mc) { + mc->add_macro_category (name, description, folders); + } +} + ApplicationBase::~ApplicationBase () { tl::set_ui_exception_handlers (0, 0, 0); diff --git a/src/lay/lay/layApplication.h b/src/lay/lay/layApplication.h index 85eb65267..887fc42c5 100644 --- a/src/lay/lay/layApplication.h +++ b/src/lay/lay/layApplication.h @@ -214,6 +214,13 @@ public: return *mp_python_interpreter; } + /** + * @brief Adds a new macro category + * + * This method is only effective when called during the autorun_early stage + */ + void add_macro_category (const std::string &name, const std::string &description, const std::vector &folders); + /** * @brief Return true, if undo buffering is enabled */ diff --git a/src/lay/lay/layMacroController.cc b/src/lay/lay/layMacroController.cc index 77bd03e20..51b1111ef 100644 --- a/src/lay/lay/layMacroController.cc +++ b/src/lay/lay/layMacroController.cc @@ -49,62 +49,27 @@ MacroController::MacroController () // .. nothing yet .. } -static lay::MacroController::MacroCategory ruby_cat () +void +MacroController::add_macro_category (const std::string &name, const std::string &description, const std::vector &folders) { lay::MacroController::MacroCategory cat; - cat.name = "macros"; - cat.description = tl::to_string (QObject::tr ("Ruby")); - cat.folders.push_back ("macros"); - cat.folders.push_back ("ruby"); - return cat; -} - -static lay::MacroController::MacroCategory python_cat () -{ - lay::MacroController::MacroCategory cat; - cat.name = "pymacros"; - cat.description = tl::to_string (QObject::tr ("Python")); - cat.folders.push_back ("pymacros"); - cat.folders.push_back ("python"); - return cat; -} - -static lay::MacroController::MacroCategory drc_cat () -{ - lay::MacroController::MacroCategory cat; - cat.name = "drc"; - cat.description = tl::to_string (QObject::tr ("DRC")); - cat.folders.push_back ("drc"); - return cat; -} - -static lay::MacroController::MacroCategory lvs_cat () -{ - lay::MacroController::MacroCategory cat; - cat.name = "lvs"; - cat.description = tl::to_string (QObject::tr ("LVS")); - cat.folders.push_back ("lvs"); - return cat; + cat.name = name; + cat.description = description; + cat.folders = folders; + m_macro_categories.push_back (cat); } void MacroController::finish () { + lym::MacroCollection::root ().clear (); + // Scan built-in macros // These macros are always taken, even if there are no macros requested (they are required to // fully form the API). lym::MacroCollection::root ().add_folder (tl::to_string (QObject::tr ("Built-In")), ":/built-in-macros", "macros", true); lym::MacroCollection::root ().add_folder (tl::to_string (QObject::tr ("Built-In")), ":/built-in-pymacros", "pymacros", true); - // TODO: consider adding "drc" and "lvs" dynamically and allow more dynamic categories - // We can do so if we first load the macros with the initial interpreters, then do autorun (which creates DSL interpreters) and then - // register the remaining categories. - - m_macro_categories.push_back (ruby_cat ()); - m_macro_categories.push_back (python_cat ()); - m_macro_categories.push_back (drc_cat ()); - m_macro_categories.push_back (lvs_cat ()); - // scans the macros from techs and packages (this will allow autorun-early on them) // and updates m_external_paths sync_macro_sources (); diff --git a/src/lay/lay/layMacroController.h b/src/lay/lay/layMacroController.h index 757d92653..cae8e979b 100644 --- a/src/lay/lay/layMacroController.h +++ b/src/lay/lay/layMacroController.h @@ -147,10 +147,16 @@ public: /** * @brief Loads the macros from the predefined paths and establishes the search paths - * This method will also establish the macro categories. + * This method can be called multiple times. */ void finish (); + /** + * @brief Adds a new macro category + * finish() needs to be called after adding a new category. + */ + void add_macro_category (const std::string &name, const std::string &description, const std::vector &folders); + /** * @brief Adds a temporary macro * diff --git a/src/lvs/lvs/built-in-macros/lvs_interpreters.lym b/src/lvs/lvs/built-in-macros/lvs_interpreters.lym index f9f9863f8..24cd20021 100644 --- a/src/lvs/lvs/built-in-macros/lvs_interpreters.lym +++ b/src/lvs/lvs/built-in-macros/lvs_interpreters.lym @@ -159,6 +159,11 @@ module LVS LVSInterpreter::new(lvs_recipe) LVSPlainTextInterpreter::new(lvs_recipe) + # Creates a new macro category + if RBA::Application::instance + RBA::Application::instance.add_macro_category("lvs", "LVS", [ "lvs" ]) + end + end diff --git a/src/lym/lym/lymMacro.cc b/src/lym/lym/lymMacro.cc index 8067b67df..f7e34fe36 100644 --- a/src/lym/lym/lymMacro.cc +++ b/src/lym/lym/lymMacro.cc @@ -46,6 +46,8 @@ #include #include +#include +#include namespace lym { @@ -1065,6 +1067,11 @@ MacroCollection::MacroCollection () } MacroCollection::~MacroCollection () +{ + do_clear (); +} + +void MacroCollection::do_clear () { for (iterator m = begin (); m != end (); ++m) { delete m->second; @@ -1513,6 +1520,13 @@ void MacroCollection::scan (const std::string &path) } } +void MacroCollection::clear () +{ + begin_changes (); + do_clear (); + on_changed (); +} + void MacroCollection::erase (lym::Macro *mp) { for (iterator m = m_macros.begin (); m != m_macros.end (); ++m) { @@ -1861,30 +1875,42 @@ bool MacroCollection::has_autorun_early () const return has_autorun_for (*this, true); } -static void autorun_for (lym::MacroCollection &collection, bool early) +static void autorun_for (lym::MacroCollection &collection, bool early, std::set *executed_already) { for (lym::MacroCollection::child_iterator c = collection.begin_children (); c != collection.end_children (); ++c) { - autorun_for (*c->second, early); + autorun_for (*c->second, early, executed_already); } for (lym::MacroCollection::iterator c = collection.begin (); c != collection.end (); ++c) { + if (c->second->can_run () && ((early && c->second->is_autorun_early ()) || (!early && c->second->is_autorun () && !c->second->is_autorun_early ()))) { - BEGIN_PROTECTED_SILENT - c->second->run (); - c->second->install_doc (); - END_PROTECTED_SILENT + + if (!executed_already || executed_already->find (c->second->path ()) == executed_already->end ()) { + + BEGIN_PROTECTED_SILENT + c->second->run (); + c->second->install_doc (); + END_PROTECTED_SILENT + + if (executed_already) { + executed_already->insert (c->second->path ()); + } + + } + } + } } -void MacroCollection::autorun () +void MacroCollection::autorun (std::set *already_executed) { - autorun_for (*this, false); + autorun_for (*this, false, already_executed); } -void MacroCollection::autorun_early () +void MacroCollection::autorun_early (std::set *already_executed) { - autorun_for (*this, true); + autorun_for (*this, true, already_executed); } void MacroCollection::dump (int l) diff --git a/src/lym/lym/lymMacro.h b/src/lym/lym/lymMacro.h index 396bdbee3..063901ca4 100644 --- a/src/lym/lym/lymMacro.h +++ b/src/lym/lym/lymMacro.h @@ -845,6 +845,12 @@ public: */ void add_unspecific (lym::Macro *m); + /** + * @brief Empties the collection + * Note: only the unspecific on_changed event is generated. + */ + void clear (); + /** * @brief Erases the given macro from the list * @@ -995,7 +1001,7 @@ public: /** * @brief Runs all macros marked with auto-run */ - void autorun (); + void autorun (std::set *already_executed = 0); /** * @brief Returns true, if the collection has an early autorun macro @@ -1005,7 +1011,7 @@ public: /** * @brief Runs all macros marked with early auto-run */ - void autorun_early (); + void autorun_early (std::set *already_executed = 0); /** * @brief Redo the scan (will add new files or folders) @@ -1129,6 +1135,8 @@ private: m_readonly = f; } + void do_clear (); + // no copying MacroCollection (const MacroCollection &d); MacroCollection &operator= (const MacroCollection &d); From fdb7d90550c7c18d8ba88219e4b5a405a8868bd0 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 24 Feb 2022 00:34:30 +0100 Subject: [PATCH 7/9] Introducing auto-run priorities for macros --- src/lay/lay/MacroPropertiesDialog.ui | 46 ++++++++++--- src/lay/lay/layMacroPropertiesDialog.cc | 5 ++ src/lym/lym/lymMacro.cc | 90 +++++++++++++++++++++---- src/lym/lym/lymMacro.h | 15 +++++ 4 files changed, 134 insertions(+), 22 deletions(-) diff --git a/src/lay/lay/MacroPropertiesDialog.ui b/src/lay/lay/MacroPropertiesDialog.ui index d7a2c29e8..1a281dac4 100644 --- a/src/lay/lay/MacroPropertiesDialog.ui +++ b/src/lay/lay/MacroPropertiesDialog.ui @@ -100,7 +100,6 @@ - 75 true @@ -224,25 +223,56 @@ 6 + + + Priority + + + + Prolog - - - - - - - + Epilog + + + + + 0 + 0 + + + + + + + + for autorun: 0 = first, 1 = second ... + + + + + + + + 1 + 0 + + + + + + + diff --git a/src/lay/lay/layMacroPropertiesDialog.cc b/src/lay/lay/layMacroPropertiesDialog.cc index 58fcf16f5..2c04a77c8 100644 --- a/src/lay/lay/layMacroPropertiesDialog.cc +++ b/src/lay/lay/layMacroPropertiesDialog.cc @@ -75,6 +75,7 @@ MacroPropertiesDialog::update (const lym::Macro *macro) propertiesFrame->setEnabled (! macro->is_readonly ()); description->setText (tl::to_qstring (macro->description ())); version->setText (tl::to_qstring (macro->version ())); + priority->setText (tl::to_qstring (tl::to_string (macro->priority ()))); prolog->setText (tl::to_qstring (macro->prolog ())); epilog->setText (tl::to_qstring (macro->epilog ())); autorun->setChecked (macro->is_autorun ()); @@ -98,6 +99,10 @@ MacroPropertiesDialog::commit (lym::Macro *macro) macro->set_show_in_menu (showmenu->isChecked ()); macro->set_group_name (tl::to_string (groupName->text ())); macro->set_menu_path (tl::to_string (menuPath->text ())); + + int p = 0; + tl::from_string (tl::to_string (priority->text ()), p); + macro->set_priority (p); } } diff --git a/src/lym/lym/lymMacro.cc b/src/lym/lym/lymMacro.cc index f7e34fe36..429a4fbf2 100644 --- a/src/lym/lym/lymMacro.cc +++ b/src/lym/lym/lymMacro.cc @@ -55,7 +55,7 @@ namespace lym // ---------------------------------------------------------------------- Macro::Macro () - : m_modified (true), m_readonly (false), m_autorun (false), m_autorun_default (false), m_autorun_early (false), m_show_in_menu (false), m_is_file (false), mp_parent (0), m_interpreter (None), m_format (Macro::NoFormat) + : m_modified (true), m_readonly (false), m_autorun (false), m_autorun_default (false), m_autorun_early (false), m_priority (0), m_show_in_menu (false), m_is_file (false), mp_parent (0), m_interpreter (None), m_format (Macro::NoFormat) { // .. nothing yet .. } @@ -89,6 +89,7 @@ void Macro::assign (const lym::Macro &other) m_autorun = other.m_autorun; m_autorun_default = other.m_autorun_default; m_autorun_early = other.m_autorun_early; + m_priority = other.m_priority; m_show_in_menu = other.m_show_in_menu; m_shortcut = other.m_shortcut; m_format = other.m_format; @@ -113,6 +114,7 @@ bool Macro::operator== (const Macro &other) const m_text == other.m_text && m_autorun == other.m_autorun && m_autorun_early == other.m_autorun_early && + m_priority == other.m_priority && m_show_in_menu == other.m_show_in_menu && m_shortcut == other.m_shortcut && m_interpreter == other.m_interpreter && @@ -184,6 +186,7 @@ static tl::XMLStruct xml_struct ("klayout-macro", tl::make_member (&Macro::doc, &Macro::set_doc, "doc") + tl::make_member (&Macro::is_autorun, &Macro::set_autorun, "autorun") + tl::make_member (&Macro::is_autorun_early, &Macro::set_autorun_early, "autorun-early") + + tl::make_member (&Macro::priority, &Macro::set_priority, "priority") + tl::make_member (&Macro::shortcut, &Macro::set_shortcut, "shortcut") + tl::make_member (&Macro::show_in_menu, &Macro::set_show_in_menu, "show-in-menu") + tl::make_member (&Macro::group_name, &Macro::set_group_name, "group-name") + @@ -552,19 +555,22 @@ struct PropertyField void (lym::Macro::*string_setter) (const std::string &); bool (lym::Macro::*bool_getter) () const; void (lym::Macro::*bool_setter) (bool); + int (lym::Macro::*int_getter) () const; + void (lym::Macro::*int_setter) (int); }; static PropertyField property_fields[] = { - { "description", &lym::Macro::description, &lym::Macro::set_description, 0, 0 }, - { "prolog", &lym::Macro::prolog, &lym::Macro::set_prolog, 0, 0 }, - { "epilog", &lym::Macro::epilog, &lym::Macro::set_epilog, 0, 0 }, - { "version", &lym::Macro::version, &lym::Macro::set_version, 0, 0 }, - { "autorun", 0, 0, &lym::Macro::is_autorun, &lym::Macro::set_autorun }, - { "autorun-early", 0, 0, &lym::Macro::is_autorun_early, &lym::Macro::set_autorun_early}, - { "show-in-menu", 0, 0, &lym::Macro::show_in_menu, &lym::Macro::set_show_in_menu }, - { "group-name", &lym::Macro::group_name, &lym::Macro::set_group_name, 0, 0 }, - { "menu-path", &lym::Macro::menu_path, &lym::Macro::set_menu_path, 0, 0 }, - { "shortcut", &lym::Macro::shortcut, &lym::Macro::set_shortcut, 0, 0 } + { "description", &lym::Macro::description, &lym::Macro::set_description, 0, 0, 0, 0 }, + { "prolog", &lym::Macro::prolog, &lym::Macro::set_prolog, 0, 0, 0, 0 }, + { "epilog", &lym::Macro::epilog, &lym::Macro::set_epilog, 0, 0, 0, 0 }, + { "version", &lym::Macro::version, &lym::Macro::set_version, 0, 0, 0, 0 }, + { "autorun", 0, 0, &lym::Macro::is_autorun, &lym::Macro::set_autorun, 0, 0 }, + { "autorun-early", 0, 0, &lym::Macro::is_autorun_early, &lym::Macro::set_autorun_early, 0, 0 }, + { "show-in-menu", 0, 0, &lym::Macro::show_in_menu, &lym::Macro::set_show_in_menu, 0, 0 }, + { "group-name", &lym::Macro::group_name, &lym::Macro::set_group_name, 0, 0, 0, 0 }, + { "menu-path", &lym::Macro::menu_path, &lym::Macro::set_menu_path, 0, 0, 0, 0 }, + { "shortcut", &lym::Macro::shortcut, &lym::Macro::set_shortcut, 0, 0, 0, 0 }, + { "priority", 0, 0, 0, 0, &lym::Macro::priority, &lym::Macro::set_priority } }; static std::string escape_pta_string (const char *cp) @@ -625,6 +631,11 @@ void Macro::sync_text_with_properties () if (v) { new_lines.push_back (std::string ("# $") + pf->name); } + } else if (pf->int_getter) { + int v = (this->*(pf->int_getter)) (); + if (v) { + new_lines.push_back (std::string ("# $") + pf->name + ": " + tl::to_string (v)); + } } } @@ -672,6 +683,8 @@ void Macro::sync_properties_with_text () (this->*(pf->string_setter)) (std::string ()); } else if (pf->bool_setter) { (this->*(pf->bool_setter)) (false); + } else if (pf->int_setter) { + (this->*(pf->int_setter)) (0); } } @@ -696,6 +709,10 @@ void Macro::sync_properties_with_text () (this->*(pf->string_setter)) (unescape_pta_string (pex.skip ())); } else if (pf->bool_setter) { (this->*(pf->bool_setter)) (true); + } else if (pf->int_setter) { + int v = 0; + tl::from_string (pex.skip (), v); + (this->*(pf->int_setter)) (v); } break; @@ -767,6 +784,15 @@ void Macro::set_autorun (bool f) } } +void Macro::set_priority (int p) +{ + if (p != m_priority) { + m_modified = true; + m_priority = p; + on_changed (); + } +} + void Macro::set_show_in_menu (bool f) { if (f != m_show_in_menu) { @@ -1875,15 +1901,38 @@ bool MacroCollection::has_autorun_early () const return has_autorun_for (*this, true); } -static void autorun_for (lym::MacroCollection &collection, bool early, std::set *executed_already) +static int collect_priority (lym::MacroCollection &collection, bool early, int from_prio) +{ + int p = -1; + + for (lym::MacroCollection::child_iterator c = collection.begin_children (); c != collection.end_children (); ++c) { + int pp = collect_priority (*c->second, early, from_prio); + if (pp >= from_prio && (p < 0 || pp < p)) { + p = pp; + } + } + + for (lym::MacroCollection::iterator c = collection.begin (); c != collection.end (); ++c) { + if (c->second->can_run () && ((early && c->second->is_autorun_early ()) || (!early && c->second->is_autorun () && !c->second->is_autorun_early ()))) { + int pp = c->second->priority (); + if (pp >= from_prio && (p < 0 || pp < p)) { + p = pp; + } + } + } + + return p; +} + +static void autorun_for_prio (lym::MacroCollection &collection, bool early, std::set *executed_already, int prio) { for (lym::MacroCollection::child_iterator c = collection.begin_children (); c != collection.end_children (); ++c) { - autorun_for (*c->second, early, executed_already); + autorun_for_prio (*c->second, early, executed_already, prio); } for (lym::MacroCollection::iterator c = collection.begin (); c != collection.end (); ++c) { - if (c->second->can_run () && ((early && c->second->is_autorun_early ()) || (!early && c->second->is_autorun () && !c->second->is_autorun_early ()))) { + if (c->second->priority () == prio && c->second->can_run () && ((early && c->second->is_autorun_early ()) || (!early && c->second->is_autorun () && !c->second->is_autorun_early ()))) { if (!executed_already || executed_already->find (c->second->path ()) == executed_already->end ()) { @@ -1903,6 +1952,19 @@ static void autorun_for (lym::MacroCollection &collection, bool early, std::set< } } +static void autorun_for (lym::MacroCollection &collection, bool early, std::set *executed_already) +{ + int prio = 0; + while (true) { + int p = collect_priority (collection, early, prio); + if (p < prio) { + break; + } + autorun_for_prio (collection, early, executed_already, p); + prio = p + 1; + } +} + void MacroCollection::autorun (std::set *already_executed) { autorun_for (*this, false, already_executed); diff --git a/src/lym/lym/lymMacro.h b/src/lym/lym/lymMacro.h index 063901ca4..619be68a6 100644 --- a/src/lym/lym/lymMacro.h +++ b/src/lym/lym/lymMacro.h @@ -430,6 +430,20 @@ public: */ void set_autorun_early (bool f); + /** + * @brief Gets the priority of the macro in autorun and autorun-early mode + * 0 is the first priority, -1 means "never execute". + */ + int priority () const + { + return m_priority; + } + + /** + * @brief Sets the priority + */ + void set_priority (int p); + /** * @brief Gets a value indicating whether the macro shall be shown in the menu */ @@ -596,6 +610,7 @@ private: bool m_autorun; bool m_autorun_default; bool m_autorun_early; + int m_priority; bool m_show_in_menu; std::string m_group_name; std::string m_menu_path; From d0d3d2a8beab0dc89f60bbe6769bb572b2f79718 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 24 Feb 2022 00:45:02 +0100 Subject: [PATCH 8/9] New integration, WIP --- .../lay_plugin/built-in-macros/_d25_engine.rb | 249 ++++++++++++++++++ .../built-in-macros/d25_install.lym | 51 ++++ .../built-in-macros/d25_interpreters.lym | 170 ++++++++++++ .../view_25d/lay_plugin/layD25Resources.qrc | 10 + .../tools/view_25d/lay_plugin/lay_plugin.pro | 3 + .../view_25d/lay_plugin/templates/d25.lym | 59 +++++ 6 files changed, 542 insertions(+) create mode 100644 src/plugins/tools/view_25d/lay_plugin/built-in-macros/_d25_engine.rb create mode 100644 src/plugins/tools/view_25d/lay_plugin/built-in-macros/d25_install.lym create mode 100644 src/plugins/tools/view_25d/lay_plugin/built-in-macros/d25_interpreters.lym create mode 100644 src/plugins/tools/view_25d/lay_plugin/layD25Resources.qrc create mode 100644 src/plugins/tools/view_25d/lay_plugin/templates/d25.lym diff --git a/src/plugins/tools/view_25d/lay_plugin/built-in-macros/_d25_engine.rb b/src/plugins/tools/view_25d/lay_plugin/built-in-macros/_d25_engine.rb new file mode 100644 index 000000000..591ea4085 --- /dev/null +++ b/src/plugins/tools/view_25d/lay_plugin/built-in-macros/_d25_engine.rb @@ -0,0 +1,249 @@ +# $autorun-early +# $priority: 1 + +require 'pathname' + +module D25 + + class D25ZInfo + + attr_accessor :layer, :zstart, :zstop, :display + + def initialize(_layer, _zstart, _zstop, _display) + self.layer = _layer + self.zstart = _zstart + self.zstop = _zstop + self.display = _display + end + + end + + class D25Display + + attr_accessor :fill, :frame, :like + + def initialize + self.fill = nil + self.frame = nil + self.like = nil + end + + end + + # The D25 engine + + class D25Engine < DRC::DRCEngine + + def initialize + + super + + @current_z = 0.0 + @zstack = [] + + # clip to layout view + if RBA::LayoutView::current + self.clip(RBA::LayoutView::current.box) + end + + end + + def z(*args) + + self._context("z") do + + layer = nil + zstart = nil + zstop = nil + height = nil + + args.each do |a| + + if a.is_a?(Range) + + zstart = a.min + zstop = a.max + + elsif a.is_a?(DRC::DRCLayer) + + if layer + raise("Duplicate layer argument") + end + layer = a + + elsif a.is_a?(1.class) || a.is_a?(1.0.class) + + if height + raise("Duplicate height specification") + end + height = a + + elsif a.is_a?(Hash) + + if a[:height] + if height + raise("Duplicate height specification") + end + height = a[:height] + end + if a[:zstart] + if zstart + raise("Duplicate zstart specification") + end + zstart = a[:zstart] + end + if a[:zstop] + if zstop + raise("Duplicate zstop specification") + end + zstop = a[:zstop] + end + invalid_keys = a.keys.select { |k| ![ :height, :zstart, :zstop ].member?(k) } + if invalid_keys.size > 0 + raise("Keyword argument(s) not understood: #{invalid_keys.collect(&:to_s).join(',')}") + end + + else + raise("Argument not understood: #{a.inspect}") + end + + end + + if ! zstart + zstart = @current_z + end + if ! zstop && ! height + raise("Either height or zstop must be specified") + elsif zstop && height + raise("Either height or zstop must be specified, not both") + end + if height + zstop = zstart + height + end + @current_z = zstop + + if ! layer + raise("No layer specified") + end + + info = D25ZInfo::new(layer.data, zstart, zstop, @display || D25Display::new) + @zstack << info + + return info + + end + + end + + def display(*args, &block) + + display = D25Display::new + + args.each do |a| + + if a.is_a?(D25ZInfo) + + @zstack.each do |z| + if z == a + z.display = display + end + end + + elsif a.is_a?(Hash) + + hollow_fill = 0xffffffff + + if a[:color] + if !a[:color].is_a?(0xffffff.class) + raise("'color' must be a color value (an integer)") + end + display.fill = a[:color] + display.frame = a[:color] + end + if a[:frame] + if !a[:frame].is_a?(0xffffff.class) + raise("'frame' must be a color value (an integer)") + end + display.frame = a[:frame] + end + if a[:fill] + if !a[:fill].is_a?(0xffffff.class) + raise("'fill' must be a color value (an integer)") + end + display.fill = a[:fill] + end + if a[:hollow] + if a[:hollow] + display.fill = hollow_fill + end + end + + if a[:like] + li = nil + if a[:like].is_a?(String) + li = RBA::LayerInfo::from_string(a[:like]) + elsif a[:like].is_a?(RBA::LayerInfo) + li = a[:like] + else + raise("'like' must be a string or LayerInfo object") + end + display.like = li + end + + invalid_keys = a.keys.select { |k| ![ :fill, :frame, :color, :hollow, :like ].member?(k) } + if invalid_keys.size > 0 + raise("Keyword argument(s) not understood: #{invalid_keys.collect(&:to_s).join(',')}") + end + + else + raise("Argument not understood: #{a.inspect}") + end + + end + + end + + def _finish(final = true) + + if final && @zstack.empty? + raise("No z calls made in 2.5d script") + end + + super(final) + + if final + + view = RBA::LayoutView::current.open_d25_view + + begin + + displays = {} + + @zstack.each do |z| + (displays[z.display.object_id] ||= []) << z + end + + displays.each do |k,zz| + display = zz[0].display + view.open_display(display.frame, display.fill, display.like) + zz.each do |z| + view.entry(z.layer, z.start, z.zstop) + end + view.close_display + end + + view.finish + + rescue => ex + view.close + raise ex + end + + end + + end + + end + +end + diff --git a/src/plugins/tools/view_25d/lay_plugin/built-in-macros/d25_install.lym b/src/plugins/tools/view_25d/lay_plugin/built-in-macros/d25_install.lym new file mode 100644 index 000000000..6e0ebc18f --- /dev/null +++ b/src/plugins/tools/view_25d/lay_plugin/built-in-macros/d25_install.lym @@ -0,0 +1,51 @@ + + + + + + + + + true + false + + false + + + ruby + + +module D25 + + # Installs the home menu entries (needs to be done on autorun, not autorun-early) + + if RBA::Application::instance && RBA::Application::instance.main_window + + cat = "d25" + name = "2.5d" + + mw = RBA::Application::instance.main_window + mw.menu.insert_menu("tools_menu.verification_group+", "d25", "2.5d View") + + @new_action = RBA::Action::new + @new_action.title = "New #{name} Script" + @new_action.on_triggered do + mw.show_macro_editor(cat, true) + end + + mw.menu.insert_item("tools_menu.#{cat}.end", "new_script", @new_action) + + @edit_action = RBA::Action::new + @edit_action.title = "Edit #{name} Script" + @edit_action.on_triggered do + mw.show_macro_editor(cat, false) + end + + mw.menu.insert_item("tools_menu.#{cat}.end", "edit_script", @edit_action) + + end + +end + + + diff --git a/src/plugins/tools/view_25d/lay_plugin/built-in-macros/d25_interpreters.lym b/src/plugins/tools/view_25d/lay_plugin/built-in-macros/d25_interpreters.lym new file mode 100644 index 000000000..fbf0dc9ef --- /dev/null +++ b/src/plugins/tools/view_25d/lay_plugin/built-in-macros/d25_interpreters.lym @@ -0,0 +1,170 @@ + + + + + + + + + false + true + + false + + + ruby + + +module D25 + + class D25Executable < RBA::Executable + + def initialize(macro, generator, rdb_index = nil) + + @d25 = D25Engine::new + @d25._rdb_index = rdb_index + @d25._generator = generator + + @macro = macro + + end + + def execute + + @d25._start("D25: " + @macro.path) + + # Set a debugger scope so that our errors end up with the debugger set to the D25's line + RBA::MacroExecutionContext::set_debugger_scope(@macro.path) + + begin + + # No verbosity set in d25 engine - we cannot use the engine's logger + RBA::Logger::verbosity >= 10 && RBA::Logger::info("Running #{@macro.path}") + @d25.instance_eval(@macro.text, @macro.path) + + rescue => ex + + @d25.error("In #{@macro.path}: #{ex.to_s}") + RBA::MacroExecutionContext::ignore_next_exception + raise ex + + end + + nil + + end + + def cleanup + + # Remove the debugger scope + RBA::MacroExecutionContext::remove_debugger_scope + + # cleans up and creates layout and report views + @d25._finish + + end + + end + + # A DSL implementation for a D25 language (XML format) + class D25Interpreter < RBA::MacroInterpreter + + # Constructor + def initialize(recipe) + + @recipe = recipe + + # Make the DSL use ruby syntax highlighting + self.syntax_scheme = "ruby" + self.suffix = "lyd25" + self.debugger_scheme = RBA::MacroInterpreter::RubyDebugger + self.storage_scheme = RBA::MacroInterpreter::MacroFormat + self.description = "D25" + + # Registers the new interpreter + register("d25-dsl-xml") + + # create a template for the macro editor: + create_template(":/d25-templates/d25.lym") + + # if available, create a menu branch + if RBA::Application::instance && RBA::Application::instance.main_window + mw = RBA::Application::instance.main_window + mw.menu.insert_menu("tools_menu.verification_group+", "d25", "2.5d View") + end + + end + + # Implements the execute method + def executable(macro) + D25Executable::new(macro, @recipe.generator("script" => macro.path)) + end + + end + + # A DSL implementation for a D25 language (Plain text format) + class D25PlainTextInterpreter < RBA::MacroInterpreter + + # Constructor + def initialize(recipe) + + @recipe = recipe + + # Make the DSL use ruby syntax highlighting + self.syntax_scheme = "ruby" + self.suffix = "d25" + self.debugger_scheme = RBA::MacroInterpreter::RubyDebugger + self.storage_scheme = RBA::MacroInterpreter::PlainTextWithHashAnnotationsFormat + self.description = "D25 (Text)" + + # Registers the new interpreter + register("d25-dsl") + + end + + # Implements the execute method + def executable(macro) + D25Executable::new(macro, @recipe.generator("script" => macro.path)) + end + + end + + # A recipe implementation allowing the D25 run to be redone + class D25Recipe < RBA::Recipe + + def initialize + super("d25", "D25 recipe") + end + + def executable(params) + + script = params["script"] + if ! script + return + end + + macro = RBA::Macro::macro_by_path(script) + macro || raise("Can't find D25 script #{script} - unable to re-run") + + D25Executable::new(macro, self.generator("script" => script), params["rdb_index"]) + + end + + end + + # Register the recipe + d25_recipe = D25Recipe::new + + # Register the new interpreters + D25Interpreter::new(d25_recipe) + D25PlainTextInterpreter::new(d25_recipe) + + # Creates a new macro category + if RBA::Application::instance + RBA::Application::instance.add_macro_category("d25", "2.5d view", [ "d25" ]) + end + +end + + + diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25Resources.qrc b/src/plugins/tools/view_25d/lay_plugin/layD25Resources.qrc new file mode 100644 index 000000000..be37f46fe --- /dev/null +++ b/src/plugins/tools/view_25d/lay_plugin/layD25Resources.qrc @@ -0,0 +1,10 @@ + + + built-in-macros/_d25_engine.rb + built-in-macros/d25_interpreters.lym + built-in-macros/d25_install.lym + + + templates/d25.lym + + diff --git a/src/plugins/tools/view_25d/lay_plugin/lay_plugin.pro b/src/plugins/tools/view_25d/lay_plugin/lay_plugin.pro index b05f93e94..cc6063840 100644 --- a/src/plugins/tools/view_25d/lay_plugin/lay_plugin.pro +++ b/src/plugins/tools/view_25d/lay_plugin/lay_plugin.pro @@ -26,6 +26,9 @@ SOURCES = \ FORMS = \ D25View.ui \ +RESOURCES = \ + layD25Resources.qrc \ + greaterThan(QT_MAJOR_VERSION, 5) { QT += openglwidgets } diff --git a/src/plugins/tools/view_25d/lay_plugin/templates/d25.lym b/src/plugins/tools/view_25d/lay_plugin/templates/d25.lym new file mode 100644 index 000000000..ac0468824 --- /dev/null +++ b/src/plugins/tools/view_25d/lay_plugin/templates/d25.lym @@ -0,0 +1,59 @@ + + + General;;2.5d view generator script (*.lyd25)\nA script generating a 2.5d view + + d25 + + + + false + false + + true + d25_scripts + tools_menu.d25.end + ruby + + +# Read about 2.5d generator scripts in the User Manual in "Various Topics/The 2.5d View" + +# The script utilizes the DRC language with these two extensions +# +# z(layer, options ...): +# +# This function generates a extruded view from the given layer. +# The "options" describe the z extension. Valid forms are: +# +# z(layer, 0.1 .. 0.2) extrude layer to z = 0.1 to 0.2 um +# z(layer, zstart: 0.1, zstop: 0.2) same as above +# z(layer, zstart: 0.1, height: 0.1) same as above, but with height instead of zstop +# z(layer, height: 200.nm) extrude layer from last z position with a height of 200nm +# +# If layer is an original layer, the display options (colors, hollow) are taken +# from the original layer's display style. Otherwise KLayout decides about the +# initial display options. Use "display(...)" to control the display options. +# +# display(options) { block } +# display(z(...), z(...), ..., options): +# +# Specify the display options to use for the layers generated inside the block +# (which must contains at least one "z" call) or the given z calls: +# +# Options are: +# +# display(..., color: 0xff0000) use bright red for the material color (RGB) +# display(..., frame: 0xff0000) use bright red for the frame color (combine with "color" for the fill) +# display(..., hollow: true) use hollow style (only frame is drawn) +# display(..., like: "7/0") borrow style from layout view's style for layer "7/0" +# + +z(input(1, 0), 0.1 .. 0.2) + +display(like: 7/0) do + z(input(7, 0), height: 100.nm) + z(input(8, 0), height: 150.nm) +end + + + + From c030c844bb5997bee2516f4db73fd4959a06852a Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 27 Feb 2022 21:33:26 +0100 Subject: [PATCH 9/9] Doc update --- .../view_25d/lay_plugin/built-in-macros/d25_interpreters.lym | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/tools/view_25d/lay_plugin/built-in-macros/d25_interpreters.lym b/src/plugins/tools/view_25d/lay_plugin/built-in-macros/d25_interpreters.lym index fbf0dc9ef..e85d1a45f 100644 --- a/src/plugins/tools/view_25d/lay_plugin/built-in-macros/d25_interpreters.lym +++ b/src/plugins/tools/view_25d/lay_plugin/built-in-macros/d25_interpreters.lym @@ -161,7 +161,7 @@ module D25 # Creates a new macro category if RBA::Application::instance - RBA::Application::instance.add_macro_category("d25", "2.5d view", [ "d25" ]) + RBA::Application::instance.add_macro_category("d25", "2.5d View", [ "d25" ]) end end