diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index d8c9114d5..71748e2e0 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -1366,10 +1366,38 @@ compute_area_and_perimeter_of_net_shapes (const db::hier_clusters perimeter = ap_collector.perimeter (); } +namespace { + +class AntennaShapeGenerator + : public PolygonSink +{ +public: + AntennaShapeGenerator (db::Layout *layout, db::Shapes &shapes, db::properties_id_type prop_id) + : PolygonSink (), mp_layout (layout), mp_shapes (&shapes), m_prop_id (prop_id) + { } + + virtual void put (const db::Polygon &polygon) + { + if (m_prop_id != 0) { + mp_shapes->insert (db::PolygonRefWithProperties (db::PolygonRef (polygon, mp_layout->shape_repository ()), m_prop_id)); + } else { + mp_shapes->insert (db::PolygonRef (polygon, mp_layout->shape_repository ())); + } + } + +private: + db::Layout *mp_layout; + db::Shapes *mp_shapes; + db::properties_id_type m_prop_id; +}; + +} + static db::Point -get_merged_shapes_of_net (const db::hier_clusters &clusters, db::cell_index_type ci, size_t cid, unsigned int layer_id, db::Shapes &shapes) +get_merged_shapes_of_net (const db::hier_clusters &clusters, db::cell_index_type ci, size_t cid, unsigned int layer_id, db::Layout *layout, db::Shapes &shapes, db::properties_id_type prop_id) { db::Point ref; + bool any_ref = false; db::EdgeProcessor ep; // count vertices and reserve space @@ -1386,7 +1414,10 @@ get_merged_shapes_of_net (const db::hier_clusters &clusters, db::c db::PolygonRef::polygon_edge_iterator e = pr.begin_edge (); if (! e.at_end ()) { // pick one reference point for the label - ref = (*e).p1 (); + if (! any_ref && (*e).p1 () < ref) { + ref = (*e).p1 (); + any_ref = true; + } ep.insert (pr, ++p); } } else { @@ -1394,7 +1425,7 @@ get_merged_shapes_of_net (const db::hier_clusters &clusters, db::c } } - db::ShapeGenerator sg (shapes); + db::AntennaShapeGenerator sg (layout, shapes, prop_id); db::PolygonGenerator pg (sg, false); db::SimpleMerge op; ep.process (pg, op); @@ -1402,52 +1433,51 @@ get_merged_shapes_of_net (const db::hier_clusters &clusters, db::c return ref; } -static std::string -create_antenna_msg (double agate, db::Polygon::area_type agate_int, double gate_area_factor, db::Polygon::perimeter_type pgate_int, double gate_perimeter_factor, - double ametal, db::Polygon::area_type ametal_int, double metal_area_factor, db::Polygon::perimeter_type pmetal_int, double metal_perimeter_factor, - const std::vector > &diodes, - const std::vector &adiodes_int, - double r, double ratio, double dbu) +static std::vector > +create_antenna_values (double agate, db::Polygon::area_type agate_int, double gate_area_factor, db::Polygon::perimeter_type pgate_int, double gate_perimeter_factor, + double ametal, db::Polygon::area_type ametal_int, double metal_area_factor, db::Polygon::perimeter_type pmetal_int, double metal_perimeter_factor, + const std::vector > &diodes, + const std::vector &adiodes_int, + double r, double ratio, double dbu) { - std::string msg; - msg += tl::sprintf ("agate_eff: %.12g, ", agate); + std::vector > values; + + values.push_back (std::make_pair ("agate_eff", agate)); if (fabs (gate_area_factor) > 1e-6) { - msg += tl::sprintf ("agate: %.12g, agate_factor: %.12g, ", agate_int * dbu * dbu, gate_area_factor); + values.push_back (std::make_pair ("agate", agate_int * dbu * dbu)); + values.push_back (std::make_pair ("agate_factor", gate_area_factor)); } if (fabs (gate_perimeter_factor) > 1e-6) { - msg += tl::sprintf ("pgate: %.12g, pgate_factor: %.12g, ", pgate_int * dbu * dbu, gate_perimeter_factor); + values.push_back (std::make_pair ("pgate", pgate_int * dbu)); + values.push_back (std::make_pair ("pgate_factor", gate_perimeter_factor)); } - msg += tl::sprintf ("ametal_eff: %.12g, ", ametal); + values.push_back (std::make_pair ("ametal_eff", ametal)); if (fabs (metal_area_factor) > 1e-6) { - msg += tl::sprintf ("ametal: %.12g, ametal_factor: %.12g, ", ametal_int * dbu * dbu, metal_area_factor); + values.push_back (std::make_pair ("ametal", ametal_int * dbu * dbu)); + values.push_back (std::make_pair ("ametal_factor", metal_area_factor)); } if (fabs (metal_perimeter_factor) > 1e-6) { - msg += tl::sprintf ("pmetal: %.12g, pmetal_factor: %.12g, ", pmetal_int * dbu * dbu, metal_perimeter_factor); + values.push_back (std::make_pair ("pmetal", pmetal_int * dbu)); + values.push_back (std::make_pair ("pmetal_factor", metal_perimeter_factor)); } if (! adiodes_int.empty ()) { - msg += "adiodes: ["; + tl::Variant adiodes; for (auto d = adiodes_int.begin (); d != adiodes_int.end (); ++d) { - if (d != adiodes_int.begin ()) { - msg += ", "; - } - msg += tl::sprintf ("%.12g", *d * dbu * dbu); + adiodes.push (*d * dbu * dbu); } - msg += "], "; + values.push_back (std::make_pair ("adiodes", adiodes)); } if (! diodes.empty ()) { - msg += "diode_factors: ["; + tl::Variant diode_factors; for (auto d = diodes.begin (); d != diodes.end (); ++d) { - if (d != diodes.begin ()) { - msg += ", "; - } - msg += tl::sprintf ("%.12g", d->second); + diode_factors.push (d->second); } - msg += "], "; + values.push_back (std::make_pair ("diode_factors", diode_factors)); } - msg += tl::sprintf ("ratio: %.12g, ", ametal / agate); - msg += tl::sprintf ("max_ratio_eff: %.12g, ", r); - msg += tl::sprintf ("max_ratio: %.12g", ratio); - return msg; + values.push_back (std::make_pair ("ratio", ametal / agate)); + values.push_back (std::make_pair ("max_ratio_eff", r)); + values.push_back (std::make_pair ("max_ratio", ratio)); + return values; } db::Region LayoutToNetlist::antenna_check (const db::Region &gate, double gate_area_factor, double gate_perimeter_factor, const db::Region &metal, double metal_area_factor, double metal_perimeter_factor, double ratio, const std::vector > &diodes, db::Texts *values) @@ -1538,25 +1568,50 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, double gate_a } if (tl::verbosity () >= 50) { - tl::info << "cell [" << ly.cell_name (*cid) << "]: " << - create_antenna_msg (agate, agate_int, gate_area_factor, pgate_int, gate_perimeter_factor, - ametal, ametal_int, metal_area_factor, pmetal_int, metal_perimeter_factor, - diodes, adiodes_int, r, ratio, dbu); + std::vector > antenna_values = + create_antenna_values (agate, agate_int, gate_area_factor, pgate_int, gate_perimeter_factor, + ametal, ametal_int, metal_area_factor, pmetal_int, metal_perimeter_factor, + diodes, adiodes_int, r, ratio, dbu); + tl::info << "cell [" << ly.cell_name (*cid) << "]: "; + for (auto v = antenna_values.begin (); v != antenna_values.end (); ++v) { + tl::info << " " << v->first << ": " << v->second.to_string (); + } } if (ametal / agate > r + db::epsilon) { db::Shapes &shapes = ly.cell (*cid).shapes (dl.layer ()); - db::Point ref = get_merged_shapes_of_net (m_net_clusters, *cid, *c, layer_of (metal), shapes); + + std::vector > antenna_values = + create_antenna_values (agate, agate_int, gate_area_factor, pgate_int, gate_perimeter_factor, + ametal, ametal_int, metal_area_factor, pmetal_int, metal_perimeter_factor, + diodes, adiodes_int, r, ratio, dbu); + + db::properties_id_type prop_id = 0; + if (! values) { + db::PropertiesRepository::properties_set ps; + for (auto v = antenna_values.begin (); v != antenna_values.end (); ++v) { + ps.insert (std::make_pair (ly.properties_repository ().prop_name_id (v->first), v->second)); + } + prop_id = ly.properties_repository ().properties_id (ps); + } + + db::Point ref = get_merged_shapes_of_net (m_net_clusters, *cid, *c, layer_of (metal), &ly, shapes, prop_id); if (values) { - // generate a data string with the details of the antenna computation (intentionally like JSON) - std::string msg = create_antenna_msg (agate, agate_int, gate_area_factor, pgate_int, gate_perimeter_factor, - ametal, ametal_int, metal_area_factor, pmetal_int, metal_perimeter_factor, - diodes, adiodes_int, r, ratio, dbu); - db::Shapes &shapesv = ly.cell (*cid).shapes (dlv.layer ()); + + std::string msg; + for (auto v = antenna_values.begin (); v != antenna_values.end (); ++v) { + if (v != antenna_values.begin ()) { + msg += ", "; + } + msg += v->first; + msg += ": "; + msg += v->second.to_string (); + } + shapesv.insert (db::Text (msg, db::Trans (ref - db::Point ()))); } diff --git a/src/rdb/rdb/gsiDeclRdb.cc b/src/rdb/rdb/gsiDeclRdb.cc index e42c3d02b..3b9f7a608 100644 --- a/src/rdb/rdb/gsiDeclRdb.cc +++ b/src/rdb/rdb/gsiDeclRdb.cc @@ -248,42 +248,32 @@ ItemRefUnwrappingIterator category_items_end (const rdb::Category *cat) return cat->database ()->items_by_category (cat->id ()).second; } -static void scan_layer1 (rdb::Category *cat, const db::Layout &layout, unsigned int layer) +static void scan_layer (rdb::Category *cat, const db::Layout &layout, unsigned int layer, const db::Cell *from_cell, int levels, bool with_properties) { - rdb::scan_layer (cat, layout, layer); + rdb::scan_layer (cat, layout, layer, from_cell, levels, with_properties); } -static void scan_layer2 (rdb::Category *cat, const db::Layout &layout, unsigned int layer, const db::Cell *from_cell) +static void scan_shapes (rdb::Category *cat, const db::RecursiveShapeIterator &iter, bool flat, bool with_properties) { - rdb::scan_layer (cat, layout, layer, from_cell); + rdb::scan_layer (cat, iter, flat, with_properties); } -static void scan_layer3 (rdb::Category *cat, const db::Layout &layout, unsigned int layer, const db::Cell *from_cell, int levels) -{ - rdb::scan_layer (cat, layout, layer, from_cell, levels); -} - -static void scan_shapes (rdb::Category *cat, const db::RecursiveShapeIterator &iter, bool flat) -{ - rdb::scan_layer (cat, iter, flat); -} - -static void scan_region (rdb::Category *cat, rdb::Cell *cell, const db::CplxTrans &trans, const db::Region ®ion, bool flat) +static void scan_region (rdb::Category *cat, rdb::Cell *cell, const db::CplxTrans &trans, const db::Region ®ion, bool flat, bool with_properties) { std::pair it = region.begin_iter (); - rdb::scan_layer (cat, cell, trans * it.second, it.first, flat); + rdb::scan_layer (cat, cell, trans * it.second, it.first, flat, with_properties); } -static void scan_edges (rdb::Category *cat, rdb::Cell *cell, const db::CplxTrans &trans, const db::Edges &edges, bool flat) +static void scan_edges (rdb::Category *cat, rdb::Cell *cell, const db::CplxTrans &trans, const db::Edges &edges, bool flat, bool with_properties) { std::pair it = edges.begin_iter (); - rdb::scan_layer (cat, cell, trans * it.second, it.first, flat); + rdb::scan_layer (cat, cell, trans * it.second, it.first, flat, with_properties); } -static void scan_edge_pairs (rdb::Category *cat, rdb::Cell *cell, const db::CplxTrans &trans, const db::EdgePairs &edge_pairs, bool flat) +static void scan_edge_pairs (rdb::Category *cat, rdb::Cell *cell, const db::CplxTrans &trans, const db::EdgePairs &edge_pairs, bool flat, bool with_properties) { std::pair it = edge_pairs.begin_iter (); - rdb::scan_layer (cat, cell, trans * it.second, it.first, flat); + rdb::scan_layer (cat, cell, trans * it.second, it.first, flat, with_properties); } Class decl_RdbCategory ("rdb", "RdbCategory", @@ -303,7 +293,7 @@ Class decl_RdbCategory ("rdb", "RdbCategory", "\n" "This method has been introduced in version 0.23." ) + - gsi::method_ext ("scan_shapes", &scan_shapes, gsi::arg ("iter"), gsi::arg ("flat", false), + gsi::method_ext ("scan_shapes", &scan_shapes, gsi::arg ("iter"), gsi::arg ("flat", false), gsi::arg ("with_properties", true), "@brief Scans the polygon or edge shapes from the shape iterator into the category\n" "Creates RDB items for each polygon or edge shape read from the iterator and puts them into this category.\n" "A similar, but lower-level method is \\ReportDatabase#create_items with a \\RecursiveShapeIterator argument.\n" @@ -311,9 +301,11 @@ Class decl_RdbCategory ("rdb", "RdbCategory", "if the \\flat argument is false. In this case, the hierarchy the recursive shape iterator traverses is " "copied into the report database using sample references.\n" "\n" - "This method has been introduced in version 0.23. The flat mode argument has been added in version 0.26.\n" + "If 'with_properties' is true, user properties will be turned into tagged values as well.\n" + "\n" + "This method has been introduced in version 0.23. The flat mode argument has been added in version 0.26. The 'with_properties' argument has been added in version 0.28.\n" ) + - gsi::method_ext ("scan_collection", &scan_region, gsi::arg ("cell"), gsi::arg ("trans"), gsi::arg ("region"), gsi::arg ("flat", false), + gsi::method_ext ("scan_collection", &scan_region, gsi::arg ("cell"), gsi::arg ("trans"), gsi::arg ("region"), gsi::arg ("flat", false), gsi::arg ("with_properties", true), "@brief Turns the given region into a hierarchical or flat report database\n" "The exact behavior depends on the nature of the region. If the region is a hierarchical (original or deep) region " "and the 'flat' argument is false, this method will produce a hierarchical report database in the given category. " @@ -325,44 +317,36 @@ Class decl_RdbCategory ("rdb", "RdbCategory", "\n" "The transformation argument needs to supply the dbu-to-micron transformation.\n" "\n" - "This method has been introduced in version 0.26.\n" + "If 'with_properties' is true, user properties will be turned into tagged values as well.\n" + "\n" + "This method has been introduced in version 0.26. The 'with_properties' argument has been added in version 0.28.\n" ) + - gsi::method_ext ("scan_collection", &scan_edges, gsi::arg ("cell"), gsi::arg ("trans"), gsi::arg ("edges"), gsi::arg ("flat", false), + gsi::method_ext ("scan_collection", &scan_edges, gsi::arg ("cell"), gsi::arg ("trans"), gsi::arg ("edges"), gsi::arg ("flat", false), gsi::arg ("with_properties", true), "@brief Turns the given edge collection into a hierarchical or flat report database\n" "This a another flavour of \\scan_collection accepting an edge collection.\n" "\n" - "This method has been introduced in version 0.26.\n" + "If 'with_properties' is true, user properties will be turned into tagged values as well.\n" + "\n" + "This method has been introduced in version 0.26. The 'with_properties' argument has been added in version 0.28.\n" ) + - gsi::method_ext ("scan_collection", &scan_edge_pairs, gsi::arg ("cell"), gsi::arg ("trans"), gsi::arg ("edge_pairs"), gsi::arg ("flat", false), + gsi::method_ext ("scan_collection", &scan_edge_pairs, gsi::arg ("cell"), gsi::arg ("trans"), gsi::arg ("edge_pairs"), gsi::arg ("flat", false), gsi::arg ("with_properties", true), "@brief Turns the given edge pair collection into a hierarchical or flat report database\n" "This a another flavour of \\scan_collection accepting an edge pair collection.\n" "\n" - "This method has been introduced in version 0.26.\n" - ) + - gsi::method_ext ("scan_layer", &scan_layer1, gsi::arg ("layout"), gsi::arg ("layer"), - "@brief Scans a layer from a layout into this category\n" - "Creates RDB items for each polygon or edge shape read from the each cell in the layout on the given layer and puts them into this category.\n" - "New cells will be generated for every cell encountered in the layout.\n" - "Other settings like database unit, description, top cell etc. are not made in the RDB.\n" + "If 'with_properties' is true, user properties will be turned into tagged values as well.\n" "\n" - "This method has been introduced in version 0.23.\n" + "This method has been introduced in version 0.26. The 'with_properties' argument has been added in version 0.28.\n" ) + - gsi::method_ext ("scan_layer", &scan_layer2, gsi::arg ("layout"), gsi::arg ("layer"), gsi::arg ("cell"), - "@brief Scans a layer from a layout into this category, starting with a given cell\n" - "Creates RDB items for each polygon or edge shape read from the cell and it's children in the layout on the given layer and puts them into this category.\n" - "New cells will be generated when required.\n" - "Other settings like database unit, description, top cell etc. are not made in the RDB.\n" - "\n" - "This method has been introduced in version 0.23.\n" - ) + - gsi::method_ext ("scan_layer", &scan_layer3, gsi::arg ("layout"), gsi::arg ("layer"), gsi::arg ("cell"), gsi::arg ("levels"), + gsi::method_ext ("scan_layer", &scan_layer, gsi::arg ("layout"), gsi::arg ("layer"), gsi::arg ("cell", (const db::Cell *) 0, "nil"), gsi::arg ("levels", -1), gsi::arg ("with_properties", true), "@brief Scans a layer from a layout into this category, starting with a given cell and a depth specification\n" "Creates RDB items for each polygon or edge shape read from the cell and it's children in the layout on the given layer and puts them into this category.\n" "New cells will be generated when required.\n" "\"levels\" is the number of hierarchy levels to take the child cells from. 0 means to use only \"cell\" and don't descend, -1 means \"all levels\".\n" "Other settings like database unit, description, top cell etc. are not made in the RDB.\n" "\n" - "This method has been introduced in version 0.23.\n" + "If 'with_properties' is true, user properties will be turned into tagged values as well.\n" + "\n" + "This method has been introduced in version 0.23. The 'with_properties' argument has been added in version 0.28.\n" ) + gsi::method ("name", &rdb::Category::name, "@brief Gets the category name\n" @@ -1209,7 +1193,7 @@ Class decl_ReportDatabase ("rdb", "ReportDatabase", "\n" "This convenience method has been added in version 0.25.\n" ) + - gsi::method_ext ("create_items", &rdb::create_items_from_iterator, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("iter"), + gsi::method_ext ("create_items", &rdb::create_items_from_iterator, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("iter"), gsi::arg ("with_properties", true), "@brief Creates new items from a shape iterator\n" "This method takes the shapes from the given iterator and produces items from them.\n" "It accepts various kind of shapes, such as texts, polygons, boxes and paths and " @@ -1217,39 +1201,42 @@ Class decl_ReportDatabase ("rdb", "ReportDatabase", "A similar method, which is intended for production of polygon or edge error layers and also provides hierarchical database " "construction is \\RdbCategory#scan_shapes.\n" "\n" - "This method has been introduced in version 0.25.3.\n" + "This method has been introduced in version 0.25.3. The 'with_properties' argument has been added in version 0.28.\n" "\n" "@param cell_id The ID of the cell to which the item is associated\n" "@param category_id The ID of the category to which the item is associated\n" "@param iter The iterator (a \\RecursiveShapeIterator object) from which to take the items\n" + "@param with_properties If true, user properties will be turned into tagged values as well\n" ) + - gsi::method_ext ("create_item", &rdb::create_item_from_shape, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("trans"), gsi::arg ("shape"), + gsi::method_ext ("create_item", &rdb::create_item_from_shape, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("trans"), gsi::arg ("shape"), gsi::arg ("with_properties", true), "@brief Creates a new item from a single shape\n" "This method produces an item from the given shape.\n" "It accepts various kind of shapes, such as texts, polygons, boxes and paths and " "converts them to a corresponding item. The transformation argument can be used to " "supply the transformation that applies the database unit for example.\n" "\n" - "This method has been introduced in version 0.25.3.\n" + "This method has been introduced in version 0.25.3. The 'with_properties' argument has been added in version 0.28.\n" "\n" "@param cell_id The ID of the cell to which the item is associated\n" "@param category_id The ID of the category to which the item is associated\n" "@param shape The shape to take the geometrical object from\n" "@param trans The transformation to apply\n" + "@param with_properties If true, user properties will be turned into tagged values as well\n" ) + - gsi::method_ext ("create_items", &rdb::create_items_from_shapes, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("trans"), gsi::arg ("shapes"), + gsi::method_ext ("create_items", &rdb::create_items_from_shapes, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("trans"), gsi::arg ("shapes"), gsi::arg ("with_properties", true), "@brief Creates new items from a shape container\n" "This method takes the shapes from the given container and produces items from them.\n" "It accepts various kind of shapes, such as texts, polygons, boxes and paths and " "converts them to corresponding items. The transformation argument can be used to " "supply the transformation that applies the database unit for example.\n" "\n" - "This method has been introduced in version 0.25.3.\n" + "This method has been introduced in version 0.25.3. The 'with_properties' argument has been added in version 0.28.\n" "\n" "@param cell_id The ID of the cell to which the item is associated\n" "@param category_id The ID of the category to which the item is associated\n" "@param shapes The shape container from which to take the items\n" "@param trans The transformation to apply\n" + "@param with_properties If true, user properties will be turned into tagged values as well\n" ) + gsi::method_ext ("create_items", &rdb::create_items_from_region, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("trans"), gsi::arg ("region"), "@brief Creates new polygon items for the given cell/category combination\n" diff --git a/src/rdb/rdb/rdb.h b/src/rdb/rdb/rdb.h index 26eaafc70..9bf139de9 100644 --- a/src/rdb/rdb/rdb.h +++ b/src/rdb/rdb/rdb.h @@ -860,9 +860,11 @@ public: * @brief Add a value in a generic way */ template - void add_value (const V &v) + ValueBase *add_value (const V &v, id_type tag_id = 0) { - values ().add (new Value (v)); + ValueBase *value = new Value (v); + values ().add (value, tag_id); + return value; } /** diff --git a/src/rdb/rdb/rdbUtils.cc b/src/rdb/rdb/rdbUtils.cc index 15c1e1bc8..fd65a3d66 100644 --- a/src/rdb/rdb/rdbUtils.cc +++ b/src/rdb/rdb/rdbUtils.cc @@ -34,7 +34,7 @@ namespace rdb { void -scan_layer (rdb::Category *cat, const db::Layout &layout, unsigned int layer, const db::Cell *from, int levels) +scan_layer (rdb::Category *cat, const db::Layout &layout, unsigned int layer, const db::Cell *from, int levels, bool with_properties) { rdb::Database *rdb = cat->database (); if (! rdb) { @@ -78,7 +78,7 @@ scan_layer (rdb::Category *cat, const db::Layout &layout, unsigned int layer, co } - create_items_from_shapes (rdb, rdb_cell->id (), cat->id (), db::CplxTrans (layout.dbu ()), cell.shapes (layer)); + create_items_from_shapes (rdb, rdb_cell->id (), cat->id (), db::CplxTrans (layout.dbu ()), cell.shapes (layer), with_properties); } @@ -92,8 +92,8 @@ class CreateItemsRecursiveReceiver : public db::RecursiveShapeReceiver { public: - CreateItemsRecursiveReceiver (rdb::Category *cat, const db::CplxTrans &trans, rdb::Cell *cell) - : mp_cat (cat), mp_rdb (cat->database ()), m_trans (trans), mp_rdb_cell (cell) + CreateItemsRecursiveReceiver (rdb::Category *cat, const db::CplxTrans &trans, rdb::Cell *cell, bool with_properties) + : mp_cat (cat), mp_rdb (cat->database ()), m_trans (trans), mp_rdb_cell (cell), m_with_properties (with_properties) { // just in case the iterator is non-hierarchical if (cell) { @@ -159,7 +159,7 @@ public: virtual void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans & /*always_apply*/, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/) { tl_assert (! m_cell_stack.empty ()); - create_item_from_shape (mp_rdb, m_cell_stack.back ()->id (), mp_cat->id (), m_trans, shape); + create_item_from_shape (mp_rdb, m_cell_stack.back ()->id (), mp_cat->id (), m_trans, shape, m_with_properties); } public: @@ -169,6 +169,7 @@ public: std::map m_id_to_cell; db::CplxTrans m_trans; rdb::Cell *mp_rdb_cell; + bool m_with_properties; const rdb::Cell *cell_for_id (const db::Layout *layout, db::cell_index_type ci) { @@ -187,8 +188,8 @@ class CreateItemsFlatReceiver : public db::RecursiveShapeReceiver { public: - CreateItemsFlatReceiver (rdb::Category *cat, const db::CplxTrans &trans, rdb::Cell *cell) - : mp_cat (cat), mp_rdb (cat->database ()), m_trans (trans), mp_rdb_cell (cell) + CreateItemsFlatReceiver (rdb::Category *cat, const db::CplxTrans &trans, rdb::Cell *cell, bool with_properties) + : mp_cat (cat), mp_rdb (cat->database ()), m_trans (trans), mp_rdb_cell (cell), m_with_properties (with_properties) { // .. nothing yet .. } @@ -211,7 +212,7 @@ public: virtual void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans & /*always_apply*/, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/) { - create_item_from_shape (mp_rdb, mp_rdb_cell->id (), mp_cat->id (), m_trans * trans, shape); + create_item_from_shape (mp_rdb, mp_rdb_cell->id (), mp_cat->id (), m_trans * trans, shape, m_with_properties); } public: @@ -219,23 +220,24 @@ public: rdb::Database *mp_rdb; db::CplxTrans m_trans; const rdb::Cell *mp_rdb_cell; + bool m_with_properties; }; } void -scan_layer (rdb::Category *cat, const db::RecursiveShapeIterator &iter, bool flat) +scan_layer (rdb::Category *cat, const db::RecursiveShapeIterator &iter, bool flat, bool with_properties) { if (! iter.top_cell () || ! iter.layout ()) { return; } db::CplxTrans trans (iter.layout ()->dbu ()); - scan_layer (cat, 0, trans, iter, flat); + scan_layer (cat, 0, trans, iter, flat, with_properties); } void -scan_layer (rdb::Category *cat, rdb::Cell *cell, const db::CplxTrans &trans, const db::RecursiveShapeIterator &iter, bool flat) +scan_layer (rdb::Category *cat, rdb::Cell *cell, const db::CplxTrans &trans, const db::RecursiveShapeIterator &iter, bool flat, bool with_properties) { if (! cat->database ()) { return; @@ -243,9 +245,9 @@ scan_layer (rdb::Category *cat, rdb::Cell *cell, const db::CplxTrans &trans, con std::unique_ptr rec; if (flat) { - rec.reset (new CreateItemsFlatReceiver (cat, trans, cell)); + rec.reset (new CreateItemsFlatReceiver (cat, trans, cell, with_properties)); } else { - rec.reset (new CreateItemsRecursiveReceiver (cat, trans, cell)); + rec.reset (new CreateItemsRecursiveReceiver (cat, trans, cell, with_properties)); } db::RecursiveShapeIterator (iter).push (rec.get ()); @@ -253,37 +255,47 @@ scan_layer (rdb::Category *cat, rdb::Cell *cell, const db::CplxTrans &trans, con // ------------------------------------------------------------------------------------------------------------ -void create_items_from_iterator (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::RecursiveShapeIterator &iter) +void create_items_from_iterator (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::RecursiveShapeIterator &iter, bool with_properties) { tl_assert (iter.layout ()); double dbu = iter.layout ()->dbu (); for (db::RecursiveShapeIterator i = iter; !i.at_end (); ++i) { - std::unique_ptr value (rdb::ValueBase::create_from_shape (*i, db::CplxTrans (dbu) * i.trans ())); - if (value.get ()) { - rdb::Item *item = db->create_item (cell_id, cat_id); - item->values ().add (value.release ()); - } + create_item_from_shape (db, cell_id, cat_id, db::CplxTrans (dbu) * i.trans (), *i, with_properties); } } -void create_items_from_shapes (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const db::Shapes &shapes) +void create_items_from_shapes (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const db::Shapes &shapes, bool with_properties) { for (db::Shapes::shape_iterator s = shapes.begin (db::ShapeIterator::All); !s.at_end (); ++s) { - std::unique_ptr value (rdb::ValueBase::create_from_shape (*s, trans)); - if (value.get ()) { - rdb::Item *item = db->create_item (cell_id, cat_id); - item->values ().add (value.release ()); - } + create_item_from_shape (db, cell_id, cat_id, trans, *s, with_properties); } } -void create_item_from_shape (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const db::Shape &shape) +void create_item_from_shape (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const db::Shape &shape, bool with_properties) { std::unique_ptr value (rdb::ValueBase::create_from_shape (shape, trans)); - if (value.get ()) { - rdb::Item *item = db->create_item (cell_id, cat_id); - item->values ().add (value.release ()); + if (! value.get ()) { + return; + } + + rdb::Item *item = db->create_item (cell_id, cat_id); + item->values ().add (value.release ()); + + // translate properties + if (with_properties && shape.has_prop_id () && shape.shapes () && shape.shapes ()->cell ()) { + + const db::Layout *layout = shape.shapes ()->cell ()->layout (); + if (layout) { + + auto ps = layout->properties_repository ().properties (shape.prop_id ()); + for (auto i = ps.begin (); i != ps.end (); ++i) { + id_type tag_id = db->tags ().tag (layout->properties_repository ().prop_name (i->first).to_string (), true /*user tag*/).id (); + add_item_value (item, i->second, trans, tag_id); + } + + } + } } @@ -317,50 +329,97 @@ void create_items_from_edge_pairs (rdb::Database *db, rdb::id_type cell_id, rdb: } } -void add_item_value (rdb::Item *item, const tl::Variant &v, double dbu) +ValueBase *add_item_value (rdb::Item *item, const tl::Variant &v, const db::CplxTrans &trans, rdb::id_type tag_id) { - if (dbu > 0 && v.is_user ()) { - item->add_value (db::CplxTrans (dbu) * v.to_user ()); - } else if (dbu > 0 && v.is_user ()) { - db::DPoint p = db::CplxTrans (dbu) * v.to_user (); - item->add_value (db::DEdge (p, p)); - } else if (dbu > 0 && v.is_user ()) { - item->add_value (db::CplxTrans (dbu) * v.to_user ()); - } else if (dbu > 0 && v.is_user ()) { + if (v.is_user ()) { + return item->add_value (trans * v.to_user (), tag_id); + } else if (v.is_user ()) { + db::DPoint p = trans * v.to_user (); + return item->add_value (db::DEdge (p, p), tag_id); + } else if (v.is_user ()) { + return item->add_value (trans * v.to_user (), tag_id); + } else if (v.is_user ()) { db::DPolygon p; - db::DSimplePolygon sp = db::CplxTrans (dbu) * v.to_user (); + db::DSimplePolygon sp = trans * v.to_user (); p.assign_hull (sp.begin_hull (), sp.end_hull ()); - item->add_value (p); - } else if (dbu > 0 && v.is_user ()) { - item->add_value (db::CplxTrans (dbu) * v.to_user ()); - } else if (dbu > 0 && v.is_user ()) { - item->add_value (db::CplxTrans (dbu) * v.to_user ()); - } else if (dbu > 0 && v.is_user ()) { - item->add_value (db::CplxTrans (dbu) * v.to_user ()); - } else if (dbu > 0 && v.is_user ()) { - item->add_value (db::CplxTrans (dbu) * v.to_user ()); + return item->add_value (p, tag_id); + } else if (v.is_user ()) { + return item->add_value (trans * v.to_user (), tag_id); + } else if (v.is_user ()) { + return item->add_value (trans * v.to_user (), tag_id); + } else if (v.is_user ()) { + return item->add_value (trans * v.to_user (), tag_id); + } else if (v.is_user ()) { + return item->add_value (trans * v.to_user (), tag_id); } else if (v.is_user ()) { - item->add_value (v.to_user ()); + return item->add_value (v.to_user (), tag_id); } else if (v.is_user ()) { db::DPoint p = v.to_user (); - item->add_value (db::DEdge (p, p)); + return item->add_value (db::DEdge (p, p), tag_id); } else if (v.is_user ()) { - item->add_value (v.to_user ()); + return item->add_value (v.to_user (), tag_id); } else if (v.is_user ()) { db::DPolygon p; db::DSimplePolygon sp = v.to_user (); p.assign_hull (sp.begin_hull (), sp.end_hull ()); - item->add_value (p); + return item->add_value (p, tag_id); } else if (v.is_user ()) { - item->add_value (v.to_user ()); + return item->add_value (v.to_user (), tag_id); } else if (v.is_user ()) { - item->add_value (v.to_user ()); + return item->add_value (v.to_user (), tag_id); } else if (v.is_user ()) { - item->add_value (v.to_user ()); + return item->add_value (v.to_user (), tag_id); } else if (v.is_user ()) { - item->add_value (v.to_user ()); + return item->add_value (v.to_user (), tag_id); } else { - item->add_value (std::string (v.to_string ())); + return item->add_value (std::string (v.to_string ()), tag_id); + } +} + +ValueBase *add_item_value(rdb::Item *item, const tl::Variant &v, double dbu, rdb::id_type tag_id) +{ + if (dbu > 0 && v.is_user ()) { + return item->add_value (db::CplxTrans (dbu) * v.to_user (), tag_id); + } else if (dbu > 0 && v.is_user ()) { + db::DPoint p = db::CplxTrans (dbu) * v.to_user (); + return item->add_value (db::DEdge (p, p), tag_id); + } else if (dbu > 0 && v.is_user ()) { + return item->add_value (db::CplxTrans (dbu) * v.to_user (), tag_id); + } else if (dbu > 0 && v.is_user ()) { + db::DPolygon p; + db::DSimplePolygon sp = db::CplxTrans (dbu) * v.to_user (); + p.assign_hull (sp.begin_hull (), sp.end_hull ()); + return item->add_value (p, tag_id); + } else if (dbu > 0 && v.is_user ()) { + return item->add_value (db::CplxTrans (dbu) * v.to_user (), tag_id); + } else if (dbu > 0 && v.is_user ()) { + return item->add_value (db::CplxTrans (dbu) * v.to_user (), tag_id); + } else if (dbu > 0 && v.is_user ()) { + return item->add_value (db::CplxTrans (dbu) * v.to_user (), tag_id); + } else if (dbu > 0 && v.is_user ()) { + return item->add_value (db::CplxTrans (dbu) * v.to_user (), tag_id); + } else if (v.is_user ()) { + return item->add_value (v.to_user (), tag_id); + } else if (v.is_user ()) { + db::DPoint p = v.to_user (); + return item->add_value (db::DEdge (p, p), tag_id); + } else if (v.is_user ()) { + return item->add_value (v.to_user (), tag_id); + } else if (v.is_user ()) { + db::DPolygon p; + db::DSimplePolygon sp = v.to_user (); + p.assign_hull (sp.begin_hull (), sp.end_hull ()); + return item->add_value (p, tag_id); + } else if (v.is_user ()) { + return item->add_value (v.to_user (), tag_id); + } else if (v.is_user ()) { + return item->add_value (v.to_user (), tag_id); + } else if (v.is_user ()) { + return item->add_value (v.to_user (), tag_id); + } else if (v.is_user ()) { + return item->add_value (v.to_user (), tag_id); + } else { + return item->add_value (std::string (v.to_string ()), tag_id); } } diff --git a/src/rdb/rdb/rdbUtils.h b/src/rdb/rdb/rdbUtils.h index 32530e2f4..99135cbac 100644 --- a/src/rdb/rdb/rdbUtils.h +++ b/src/rdb/rdb/rdbUtils.h @@ -51,45 +51,63 @@ namespace rdb * * If "from" is 0, all cells will be scanned. Levels are the number of hierarchy levels scanned if * "from" is given. -1 means "all levels". + * + * If "with_properties" is true, user properties are translated into values with tags corresponding + * to the property names. */ -RDB_PUBLIC void scan_layer (rdb::Category *cat, const db::Layout &layout, unsigned int layer, const db::Cell *from_cell = 0, int levels = -1); +RDB_PUBLIC void scan_layer (rdb::Category *cat, const db::Layout &layout, unsigned int layer, const db::Cell *from_cell = 0, int levels = -1, bool with_properties = true); /** * @brief Scans a recursive shape iterator into a RDB category + * + * If "with_properties" is true, user properties are translated into values with tags corresponding + * to the property names. */ -RDB_PUBLIC void scan_layer (rdb::Category *cat, const db::RecursiveShapeIterator &iter, bool flat = false); +RDB_PUBLIC void scan_layer (rdb::Category *cat, const db::RecursiveShapeIterator &iter, bool flat = false, bool with_properties = true); /** * @brief Scans a recursive shape iterator into a RDB category * * This version allows supplying a cell and a transformation. With this information, the function can also handle * pseudo-iterators which don't deliver the information from a layout from from a plain shape collection. + * + * If "with_properties" is true, user properties are translated into values with tags corresponding + * to the property names. */ -RDB_PUBLIC void scan_layer (rdb::Category *cat, rdb::Cell *cell, const db::CplxTrans &trans, const db::RecursiveShapeIterator &iter, bool flat = false); +RDB_PUBLIC void scan_layer (rdb::Category *cat, rdb::Cell *cell, const db::CplxTrans &trans, const db::RecursiveShapeIterator &iter, bool flat = false, bool with_properties = true); /** * @brief Creates RDB items from a recursive shape iterator * * This function will produce items from the flattened shape iterator. The items will be stored under * the given cell. + * + * If "with_properties" is true, user properties are translated into values with tags corresponding + * to the property names. */ -RDB_PUBLIC void create_items_from_iterator (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::RecursiveShapeIterator &iter); +RDB_PUBLIC void create_items_from_iterator (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::RecursiveShapeIterator &iter, bool with_properties = true); /** * @brief Creates RDB items from a shape collection * * An arbitrary transformation can be applied to translate the shapes before turning them to items. * This transformation is useful for providing the DBU-to-micron conversion. + * + * If "with_properties" is true, user properties are translated into values with tags corresponding + * to the property names. */ -RDB_PUBLIC void create_items_from_shapes (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const db::Shapes &shapes); +RDB_PUBLIC void create_items_from_shapes (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const db::Shapes &shapes, bool with_properties = true); /** * @brief Creates RDB items from a single shape * * An arbitrary transformation can be applied to translate the shapes before turning them to items. * This transformation is useful for providing the DBU-to-micron conversion. + * + * If "with_properties" is true, user properties are translated into values with tags corresponding + * to the property names. */ -RDB_PUBLIC void create_item_from_shape (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const db::Shape &shape); +RDB_PUBLIC void create_item_from_shape (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const db::Shape &shape, bool with_properties = true); /** * @brief Creates RDB items from a region @@ -146,7 +164,14 @@ RDB_PUBLIC_TEMPLATE void create_items_from_sequence (rdb::Database *db, rdb::id_ * * Unknown types are converted to strings. */ -RDB_PUBLIC void add_item_value (rdb::Item *item, const tl::Variant &v, double dbu = 0.0); +RDB_PUBLIC ValueBase *add_item_value (rdb::Item *item, const tl::Variant &v, double dbu = 0.0, rdb::id_type tag_id = 0); + +/** + * @brief Creates a value from a tl::Variant + * + * This version takes a db::CplxTrans for converting integer-unit geometry objects to micron-unit ones. + */ +RDB_PUBLIC ValueBase *add_item_value(rdb::Item *item, const tl::Variant &v, const db::CplxTrans &trans, rdb::id_type tag_id = 0); }