Skip to content

Commit

Permalink
Merge pull request #1718 from KLayout/wip
Browse files Browse the repository at this point in the history
Wip
  • Loading branch information
klayoutmatthias authored May 31, 2024
2 parents 7b2a248 + 3902ad6 commit a494892
Show file tree
Hide file tree
Showing 24 changed files with 664 additions and 135 deletions.
7 changes: 5 additions & 2 deletions src/buddies/src/bd/bdReaderOptions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -197,10 +197,13 @@ GenericReaderOptions::add_options (tl::CommandLineOptions &cmd)
"--" + m_long_prefix + "blend-mode=mode", &m_cell_conflict_resolution, "Specifies how cell conflicts are resolved when using file concatenation",
"When concatenating files with '+', the reader will handle cells with identical names according to this mode:\n"
"\n"
"* 0: joins everything (unsafe)\n"
"* 0: joins everything (usually unsafe)\n"
"* 1: overwrite\n"
"* 2: skip new cell\n"
"* 3: rename cell (safe, default)"
"* 3: rename cell (safe, default)\n"
"\n"
"Mode 0 is a safe solution for the 'same hierarchy, different layers' case. Mode 3 is a safe solution for "
"joining multiple files into one and combining the hierarchy tree of all files as distinct separate trees.\n"
)
;
}
Expand Down
44 changes: 35 additions & 9 deletions src/db/db/dbCommonReader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ CommonReaderBase::rename_cell (db::Layout &layout, size_t id, const std::string

// Both cells already exist and are not identical: merge ID-declared cell into the name-declared one
layout.force_update ();
merge_cell (layout, iname->second.second, iid->second.second, true);
merge_cell (layout, iname->second.second, iid->second.second, true, false);
iid->second.second = iname->second.second;

}
Expand Down Expand Up @@ -239,18 +239,44 @@ CommonReaderBase::cell_for_instance (db::Layout &layout, const std::string &cn)
}

void
CommonReaderBase::merge_cell (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index, bool with_meta) const
CommonReaderBase::merge_cell (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index, bool with_meta, bool no_duplicate_instances) const
{
const db::Cell &src_cell = layout.cell (src_cell_index);
db::Cell &target_cell = layout.cell (target_cell_index);
target_cell.set_ghost_cell (src_cell.is_ghost_cell () && target_cell.is_ghost_cell ());

// copy over the instances
for (db::Cell::const_iterator i = src_cell.begin (); ! i.at_end (); ++i) {
// NOTE: cell indexed may be invalid because we delete subcells without update()
if (layout.is_valid_cell_index (i->cell_index ())) {
target_cell.insert (*i);
if (no_duplicate_instances) {

// avoid generating duplicates
std::set<db::Instance, db::InstanceCompareFunction> current;
for (db::Cell::const_iterator i = target_cell.begin (); ! i.at_end (); ++i) {
current.insert (*i);
}

// copy over the instances
// NOTE: need to do that in a two-step fashion as inserting instances may invalidate
// the existing ones.
std::vector<bool> selected;
for (db::Cell::const_iterator i = src_cell.begin (); ! i.at_end (); ++i) {
// NOTE: cell indexed may be invalid because we delete subcells without update()
selected.push_back (layout.is_valid_cell_index (i->cell_index ()) && current.find (*i) == current.end ());
}
auto s = selected.begin ();
for (db::Cell::const_iterator i = src_cell.begin (); ! i.at_end (); ++i, ++s) {
if (*s) {
target_cell.insert (*i);
}
}

} else {

for (db::Cell::const_iterator i = src_cell.begin (); ! i.at_end (); ++i) {
// NOTE: cell indexed may be invalid because we delete subcells without update()
if (layout.is_valid_cell_index (i->cell_index ())) {
target_cell.insert (*i);
}
}

}

merge_cell_without_instances (layout, target_cell_index, src_cell_index, with_meta);
Expand Down Expand Up @@ -385,7 +411,7 @@ CommonReaderBase::finish (db::Layout &layout)

layout.cell (ci_org).clear_shapes ();

merge_cell (layout, ci_org, ci_new, true);
merge_cell (layout, ci_org, ci_new, true, false);

} else if (m_cc_resolution == SkipNewCell && ! layout.cell (ci_org).is_ghost_cell ()) {

Expand All @@ -397,7 +423,7 @@ CommonReaderBase::finish (db::Layout &layout)

} else {

merge_cell (layout, ci_org, ci_new, m_cc_resolution != SkipNewCell);
merge_cell (layout, ci_org, ci_new, m_cc_resolution != SkipNewCell, m_cc_resolution == AddToCell);

}

Expand Down
2 changes: 1 addition & 1 deletion src/db/db/dbCommonReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ class DB_PUBLIC CommonReaderBase
/**
* @brief Merge (and delete) the src_cell into target_cell
*/
void merge_cell (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index, bool with_meta) const;
void merge_cell (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index, bool with_meta, bool no_duplicate_instances) const;

/**
* @brief Merge (and delete) the src_cell into target_cell without instances
Expand Down
15 changes: 14 additions & 1 deletion src/db/db/dbInstances.h
Original file line number Diff line number Diff line change
Expand Up @@ -1977,7 +1977,20 @@ OverlappingInstanceIteratorTraits::instance_from_stable_iter (const Iter &iter)
// box tree iterators deliver pointers, not iterators. Use instance_from_pointer to do this conversion.
return mp_insts->instance_from_pointer (&*iter);
}


/**
* @brief A compare function for db::Instance that uses "less" for value compare
*
* In contrast, "operator<" will compare the instance reference, not value.
*/
struct InstanceCompareFunction
{
bool operator() (const db::Instance &a, const db::Instance &b) const
{
return a.less (b);
}
};

}

#endif
Expand Down
77 changes: 72 additions & 5 deletions src/db/db/gsiDeclDbLayoutToNetlist.cc
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,24 @@ static std::vector<std::string> l2n_layer_names (const db::LayoutToNetlist *l2n)
return ln;
}

static std::vector<unsigned int> l2n_layer_indexes (const db::LayoutToNetlist *l2n)
{
std::vector<unsigned int> li;
for (db::LayoutToNetlist::layer_iterator l = l2n->begin_layers (); l != l2n->end_layers (); ++l) {
li.push_back (l->first);
}
return li;
}

static db::LayerProperties l2n_layer_info (const db::LayoutToNetlist *l2n, unsigned int layer)
{
if (! l2n->internal_layout () || ! l2n->internal_layout ()->is_valid_layer (layer)) {
return db::LayerProperties ();
} else {
return l2n->internal_layout ()->get_properties (layer);
}
}

static db::Region antenna_check3 (db::LayoutToNetlist *l2n, const db::Region &poly, double poly_area_factor, double poly_perimeter_factor, const db::Region &metal, double metal_area_factor, double metal_perimeter_factor, double ratio, const std::vector<tl::Variant> &diodes, db::Texts *texts)
{
std::vector<std::pair<const db::Region *, double> > diode_pairs;
Expand Down Expand Up @@ -331,7 +349,22 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
"This method has been generalized in version 0.27.\n"
) +
gsi::method_ext ("layer_names", &l2n_layer_names,
"@brief Returns a list of names of the layer kept inside the LayoutToNetlist object."
"@brief Returns a list of names of the layers kept inside the LayoutToNetlist object."
) +
gsi::method_ext ("layer_indexes", &l2n_layer_indexes,
"@brief Returns a list of indexes of the layers kept inside the LayoutToNetlist object.\n"
"You can use \\layer_name to get the name from a layer index. You can use \\layer_info to get "
"the \\LayerInfo object attached to a layer - if the layer is an original layer.\n"
"\n"
"This method has been introduced in version 0.29.2.\n"
) +
gsi::method_ext ("layer_info", &l2n_layer_info, gsi::arg ("index"),
"@brief Returns the LayerInfo object attached to a layer (by index).\n"
"If the layer is an original layer and not a derived one, this method will return the "
"stream layer information where the original layer was taken from. Otherwise an empty \\LayerInfo object "
"is returned.\n"
"\n"
"This method has been introduced in version 0.29.2.\n"
) +
gsi::factory ("layer_by_name", &db::LayoutToNetlist::layer_by_name, gsi::arg ("name"),
"@brief Gets a layer object for the given name.\n"
Expand Down Expand Up @@ -599,8 +632,10 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
) +
gsi::method_ext ("internal_layout", &l2n_internal_layout,
"@brief Gets the internal layout\n"
"Usually it should not be required to obtain the internal layout. If you need to do so, make sure not to modify the layout as\n"
"the functionality of the netlist extractor depends on it."
"The internal layout is where the LayoutToNetlist database stores the shapes for the nets. "
"Usually you do not need to access this object - you must use \\build_net or \\shapes_of_net to "
"retrieve the per-net shape information. If you access the internal layout, make sure you do not "
"modify it."
) +
gsi::method_ext ("internal_top_cell", &l2n_internal_top_cell,
"@brief Gets the internal top cell\n"
Expand Down Expand Up @@ -664,8 +699,13 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
"This method puts the shapes of a net into the given target cell using a variety of options\n"
"to represent the net name and the hierarchy of the net.\n"
"\n"
"If the netname_prop name is not nil, a property with the given name is created and assigned\n"
"the net name.\n"
"If 'netname_prop' is not nil, a property with the given name is created and attached to shapes. The value "
"of the property is the net name.\n"
"\n"
"'lmap' defines which layers are to be produced. It is map, where the keys are layer indexes in the "
"target layout and the values are Region objects indicating the layer where shapes are to be taken from. "
"Use \\layer_by_name or \\layer_by_index to get the Region object corresponding to a layer stored inside "
"the LayoutToNetlist database.\n"
"\n"
"Net hierarchy is covered in three ways:\n"
"@ul\n"
Expand Down Expand Up @@ -696,6 +736,14 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
"If no mapping is provided for a specific circuit cell, the nets are copied into the next mapped parent as "
"many times as the circuit cell appears there (circuit flattening).\n"
"\n"
"If 'netname_prop' is not nil, a property with the given name is created and attached to shapes. The value "
"of the property is the net name.\n"
"\n"
"'lmap' defines which layers are to be produced. It is map, where the keys are layer indexes in the "
"target layout and the values are Region objects indicating the layer where shapes are to be taken from. "
"Use \\layer_by_name or \\layer_by_index to get the Region object corresponding to a layer stored inside "
"the LayoutToNetlist database.\n"
"\n"
"The method has three net annotation modes:\n"
"@ul\n"
" @li No annotation (net_cell_name_prefix == nil and netname_prop == nil): the shapes will be put\n"
Expand Down Expand Up @@ -910,6 +958,25 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
"hierarchical data and an existing DeepShapeStore object, use the "
"'LayoutToNetlist(dss)' constructor.\n"
"\n"
"Once the extraction is done, you can persist the \\LayoutToNetlist object "
"using \\write and restore it using \\read. You can use the query API (see below) to "
"analyze the LayoutToNetlist database.\n"
"\n"
"The query API of the \\LayoutToNetlist object consists of the following parts:\n"
"\n"
"@ul\n"
"@li Net shape retrieval: \\build_all_nets, \\build_nets, \\build_net and \\shapes_per_net @/li\n"
"@li Layers: \\layer_by_index, \\layer_by_name, \\layer_indexes, \\layer_names, \\layer_info, \\layer_name @/li\n"
"@li Log entries: \\each_log_entry @/li\n"
"@li Probing (get net from position): \\probe_net @/li\n"
"@li Netlist: \\netlist @/li\n"
"@li Internal shape storage: \\internal_layout, \\internal_top_cell @/li\n"
"@li Helper functions: \\cell_mapping_into, \\const_cell_mapping_into @/li\n"
"@/ul\n"
"\n"
"The \\LayoutToNetlist object is also the entry point for connectivity-aware DRC checks, "
"such as antenna checks.\n"
"\n"
"This class has been introduced in version 0.26."
);

Expand Down
4 changes: 4 additions & 0 deletions src/db/unit_tests/dbCellTests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -998,6 +998,10 @@ TEST(6)
// Note: iterating and replace does not work in non-editable mode
if (db::default_editable_mode ()) {

std::vector<db::Instance> insts;
for (db::Cell::const_iterator i = cc.begin (); ! i.at_end (); ++i) {
insts.push_back (*i);
}
for (db::Cell::const_iterator i = cc.begin (); ! i.at_end (); ++i) {
cc.replace_prop_id (*i, i->prop_id () + 1);
}
Expand Down
1 change: 0 additions & 1 deletion src/db/unit_tests/dbLayoutQueryTests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1020,7 +1020,6 @@ void init_layout2 (db::Layout &g)
tl::InputStream stream (tl::testdata () + "/gds/issue-1671.gds");
db::Reader reader (stream);
reader.read (g, db::LoadLayoutOptions ());
return; // @@@

g.insert_layer (0, db::LayerProperties ("l0"));
g.insert_layer (1, db::LayerProperties ("l1"));
Expand Down
14 changes: 10 additions & 4 deletions src/gsi/gsi/gsiClass.h
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,9 @@ struct NoAdaptorTag { };
template <class X, class Adapted>
struct adaptor_type_info
{
static const std::type_info *type_info ()
typedef Adapted final_type;

static const std::type_info *type_info ()
{
return &typeid (Adapted);
}
Expand Down Expand Up @@ -476,6 +478,8 @@ struct adaptor_type_info
template <class X>
struct adaptor_type_info<X, NoAdaptorTag>
{
typedef X final_type;

static const std::type_info *type_info ()
{
return 0;
Expand Down Expand Up @@ -517,6 +521,8 @@ class GSI_PUBLIC_TEMPLATE Class
: public ClassBase
{
public:
typedef typename adaptor_type_info<X, Adapted>::final_type final_type;

Class (const std::string &module, const std::string &name, const Methods &mm, const std::string &doc = std::string (), bool do_register = true)
: ClassBase (doc, mm, do_register)
{
Expand Down Expand Up @@ -681,9 +687,9 @@ class GSI_PUBLIC_TEMPLATE Class
}

private:
gsi::VariantUserClass<X> m_var_cls;
gsi::VariantUserClass<X> m_var_cls_c;
gsi::VariantUserClass<X> m_var_cls_cls;
gsi::VariantUserClass<final_type> m_var_cls;
gsi::VariantUserClass<final_type> m_var_cls_c;
gsi::VariantUserClass<final_type> m_var_cls_cls;
std::unique_ptr<SubClassTesterBase> m_subclass_tester;
};

Expand Down
Loading

0 comments on commit a494892

Please sign in to comment.