Merge branch 'master' into drc-kissing-corners

This commit is contained in:
Matthias Koefferlein 2024-02-11 10:45:35 +01:00
commit b3d01617a7
50 changed files with 1251 additions and 87 deletions

View File

@ -20,6 +20,10 @@ buildopts=
# TODO: derive this list automatically? # TODO: derive this list automatically?
case $target in case $target in
debian12)
depends="python3-dev, libc6-dev, libgcc-s1, libgit2-1.5, libqt6core5compat6, libqt6designer6, libqt6gui6, libqt6multimedia6, libqt6multimediaquick6, libqt6network6, libqt6printsupport6, libqt6sql6, libqt6svg6, libqt6widgets6, libqt6xml6, libruby3.1, libstdc++6, zlib1g"
;;
ubuntu16) ubuntu16)
depends="libqt4-designer (>= 4.8.6), libqt4-xml (>= 4.8.6), libqt4-sql (>= 4.8.6), libqt4-network (>= 4.8.6), libqtcore4 (>= 4.8.6), libqtgui4 (>= 4.8.6), zlib1g (>= 1.2.8), libgit2-24 (>= 0.24.0), libruby2.3 (>= 2.3.1), python3 (>= 3.5.1), libpython3.5 (>= 3.5.1), libstdc++6 (>= 4.6.3), libc6 (>= 2.15)" depends="libqt4-designer (>= 4.8.6), libqt4-xml (>= 4.8.6), libqt4-sql (>= 4.8.6), libqt4-network (>= 4.8.6), libqtcore4 (>= 4.8.6), libqtgui4 (>= 4.8.6), zlib1g (>= 1.2.8), libgit2-24 (>= 0.24.0), libruby2.3 (>= 2.3.1), python3 (>= 3.5.1), libpython3.5 (>= 3.5.1), libstdc++6 (>= 4.6.3), libc6 (>= 2.15)"
# No HTTPS support - that is somewhat useless # No HTTPS support - that is somewhat useless
@ -63,7 +67,7 @@ libdir="usr/lib/klayout"
rm -rf $bininstdir rm -rf $bininstdir
# do the actual build # do the actual build
./build.sh -j2 \ ./build.sh -j$(nproc) \
-bin $bininstdir \ -bin $bininstdir \
-build $builddir \ -build $builddir \
-rpath /$libdir \ -rpath /$libdir \

View File

@ -160,7 +160,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 // Both cells already exist and are not identical: merge ID-declared cell into the name-declared one
layout.force_update (); layout.force_update ();
merge_cell (layout, iname->second.second, iid->second.second); merge_cell (layout, iname->second.second, iid->second.second, true);
iid->second.second = iname->second.second; iid->second.second = iname->second.second;
} }
@ -235,7 +235,7 @@ CommonReaderBase::cell_for_instance (db::Layout &layout, const std::string &cn)
} }
void void
CommonReaderBase::merge_cell (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index) const CommonReaderBase::merge_cell (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index, bool with_meta) const
{ {
const db::Cell &src_cell = layout.cell (src_cell_index); const db::Cell &src_cell = layout.cell (src_cell_index);
db::Cell &target_cell = layout.cell (target_cell_index); db::Cell &target_cell = layout.cell (target_cell_index);
@ -249,11 +249,11 @@ CommonReaderBase::merge_cell (db::Layout &layout, db::cell_index_type target_cel
} }
} }
merge_cell_without_instances (layout, target_cell_index, src_cell_index); merge_cell_without_instances (layout, target_cell_index, src_cell_index, with_meta);
} }
void void
CommonReaderBase::merge_cell_without_instances (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index) const CommonReaderBase::merge_cell_without_instances (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index, bool with_meta) const
{ {
const db::Cell &src_cell = layout.cell (src_cell_index); const db::Cell &src_cell = layout.cell (src_cell_index);
db::Cell &target_cell = layout.cell (target_cell_index); db::Cell &target_cell = layout.cell (target_cell_index);
@ -268,6 +268,16 @@ CommonReaderBase::merge_cell_without_instances (db::Layout &layout, db::cell_ind
// replace all instances of the new cell with the original one // replace all instances of the new cell with the original one
layout.replace_instances_of (src_cell.cell_index (), target_cell.cell_index ()); layout.replace_instances_of (src_cell.cell_index (), target_cell.cell_index ());
// merge meta info
if (with_meta) {
auto ib = layout.begin_meta (src_cell.cell_index ());
auto ie = layout.end_meta (src_cell.cell_index ());
for (auto i = ib; i != ie; ++i) {
layout.add_meta_info (target_cell.cell_index (), i->first, i->second);
}
}
layout.clear_meta (src_cell.cell_index ());
// finally delete the new cell // finally delete the new cell
layout.delete_cell (src_cell.cell_index ()); layout.delete_cell (src_cell.cell_index ());
} }
@ -371,7 +381,7 @@ CommonReaderBase::finish (db::Layout &layout)
layout.cell (ci_org).clear_shapes (); layout.cell (ci_org).clear_shapes ();
merge_cell (layout, ci_org, ci_new); merge_cell (layout, ci_org, ci_new, true);
} else if (m_cc_resolution == SkipNewCell && ! layout.cell (ci_org).is_ghost_cell ()) { } else if (m_cc_resolution == SkipNewCell && ! layout.cell (ci_org).is_ghost_cell ()) {
@ -379,11 +389,11 @@ CommonReaderBase::finish (db::Layout &layout)
layout.cell (ci_new).clear_shapes (); layout.cell (ci_new).clear_shapes ();
// NOTE: ignore instances -> this saves us a layout update // NOTE: ignore instances -> this saves us a layout update
merge_cell_without_instances (layout, ci_org, ci_new); merge_cell_without_instances (layout, ci_org, ci_new, false);
} else { } else {
merge_cell (layout, ci_org, ci_new); merge_cell (layout, ci_org, ci_new, m_cc_resolution != SkipNewCell);
} }

View File

@ -242,12 +242,12 @@ protected:
/** /**
* @brief Merge (and delete) the src_cell into target_cell * @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) const; void merge_cell (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index, bool with_meta) const;
/** /**
* @brief Merge (and delete) the src_cell into target_cell without instances * @brief Merge (and delete) the src_cell into target_cell without instances
*/ */
void merge_cell_without_instances (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index) const; void merge_cell_without_instances (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index, bool with_meta) const;
/** /**
* @brief Gets the layer name map * @brief Gets the layer name map

View File

@ -257,6 +257,83 @@ private:
bool m_insert; bool m_insert;
}; };
struct SetLayoutMetaInfoOp
: public LayoutOp
{
SetLayoutMetaInfoOp (db::Layout::meta_info_name_id_type name_id, const db::MetaInfo *f, const db::MetaInfo *t)
: m_name_id (name_id), m_has_from (f != 0), m_has_to (t != 0)
{
if (f) {
m_from = *f;
}
if (t) {
m_to = *t;
}
}
virtual void redo (db::Layout *layout) const
{
if (! m_has_to) {
layout->remove_meta_info (m_name_id);
} else {
layout->add_meta_info (m_name_id, m_to);
}
}
virtual void undo (db::Layout *layout) const
{
if (! m_has_from) {
layout->remove_meta_info (m_name_id);
} else {
layout->add_meta_info (m_name_id, m_from);
}
}
private:
db::Layout::meta_info_name_id_type m_name_id;
bool m_has_from, m_has_to;
db::MetaInfo m_from, m_to;
};
struct SetCellMetaInfoOp
: public LayoutOp
{
SetCellMetaInfoOp (db::cell_index_type ci, db::Layout::meta_info_name_id_type name_id, const db::MetaInfo *f, const db::MetaInfo *t)
: m_ci (ci), m_name_id (name_id), m_has_from (f != 0), m_has_to (t != 0)
{
if (f) {
m_from = *f;
}
if (t) {
m_to = *t;
}
}
virtual void redo (db::Layout *layout) const
{
if (! m_has_to) {
layout->remove_meta_info (m_ci, m_name_id);
} else {
layout->add_meta_info (m_ci, m_name_id, m_to);
}
}
virtual void undo (db::Layout *layout) const
{
if (! m_has_from) {
layout->remove_meta_info (m_ci, m_name_id);
} else {
layout->add_meta_info (m_ci, m_name_id, m_from);
}
}
private:
db::cell_index_type m_ci;
db::Layout::meta_info_name_id_type m_name_id;
bool m_has_from, m_has_to;
db::MetaInfo m_from, m_to;
};
// ----------------------------------------------------------------- // -----------------------------------------------------------------
// Implementation of the ProxyContextInfo class // Implementation of the ProxyContextInfo class
@ -848,6 +925,9 @@ Layout::delete_cells (const std::set<cell_index_type> &cells_to_delete)
// cell child objects that must remain. // cell child objects that must remain.
for (std::set<cell_index_type>::const_iterator c = cells_to_delete.begin (); c != cells_to_delete.end (); ++c) { for (std::set<cell_index_type>::const_iterator c = cells_to_delete.begin (); c != cells_to_delete.end (); ++c) {
// supports undo
clear_meta (*c);
if (manager () && manager ()->transacting ()) { if (manager () && manager ()->transacting ()) {
// note the "take" method - this takes out the cell // note the "take" method - this takes out the cell
@ -917,9 +997,12 @@ Layout::delete_cell (cell_index_type id)
// a backup container for the cell. This is necessary since the ID's within manager are given to // a backup container for the cell. This is necessary since the ID's within manager are given to
// cell child objects that must remain. // cell child objects that must remain.
// supports undo
clear_meta (id);
if (manager () && manager ()->transacting ()) { if (manager () && manager ()->transacting ()) {
// not the "take" method - this takes out the cell // note the "take" method - this takes out the cell
std::string cn (cell_name (id)); std::string cn (cell_name (id));
manager ()->queue (this, new NewRemoveCellOp (id, cn, true /*remove*/, take_cell (id))); manager ()->queue (this, new NewRemoveCellOp (id, cn, true /*remove*/, take_cell (id)));
@ -1869,18 +1952,36 @@ Layout::meta_info_name_id (const std::string &name) const
void void
Layout::clear_meta () Layout::clear_meta ()
{ {
if (manager () && manager ()->transacting ()) {
for (auto i = m_meta_info.begin (); i != m_meta_info.end (); ++i) {
manager ()->queue (this, new SetLayoutMetaInfoOp (i->first, &i->second, 0));
}
}
m_meta_info.clear (); m_meta_info.clear ();
} }
void void
Layout::add_meta_info (meta_info_name_id_type name_id, const MetaInfo &i) Layout::add_meta_info (meta_info_name_id_type name_id, const MetaInfo &i)
{ {
if (manager () && manager ()->transacting ()) {
auto e = m_meta_info.find (name_id);
manager ()->queue (this, new SetLayoutMetaInfoOp (name_id, e != m_meta_info.end () ? &e->second : 0, &i));
}
m_meta_info[name_id] = i; m_meta_info[name_id] = i;
} }
void void
Layout::remove_meta_info (meta_info_name_id_type name_id) Layout::remove_meta_info (meta_info_name_id_type name_id)
{ {
if (manager () && manager ()->transacting ()) {
auto e = m_meta_info.find (name_id);
if (e != m_meta_info.end ()) {
manager ()->queue (this, new SetLayoutMetaInfoOp (name_id, &e->second, 0));
}
}
m_meta_info.erase (name_id); m_meta_info.erase (name_id);
} }
@ -1901,12 +2002,41 @@ Layout::has_meta_info (meta_info_name_id_type name_id) const
void void
Layout::clear_meta (db::cell_index_type ci) Layout::clear_meta (db::cell_index_type ci)
{ {
if (manager () && manager ()->transacting ()) {
auto ib = begin_meta (ci);
auto ie = end_meta (ci);
for (auto i = ib; i != ie; ++i) {
manager ()->queue (this, new SetCellMetaInfoOp (ci, i->first, &i->second, 0));
}
}
m_meta_info_by_cell.erase (ci); m_meta_info_by_cell.erase (ci);
} }
void
Layout::clear_all_meta ()
{
clear_meta ();
while (! m_meta_info_by_cell.empty ()) {
clear_meta (m_meta_info_by_cell.begin ()->first);
}
}
void void
Layout::add_meta_info (db::cell_index_type ci, meta_info_name_id_type name_id, const MetaInfo &i) Layout::add_meta_info (db::cell_index_type ci, meta_info_name_id_type name_id, const MetaInfo &i)
{ {
if (manager () && manager ()->transacting ()) {
const MetaInfo *from = 0;
auto c = m_meta_info_by_cell.find (ci);
if (c != m_meta_info_by_cell.end ()) {
auto e = c->second.find (name_id);
if (e != c->second.end ()) {
from = &e->second;
}
}
manager ()->queue (this, new SetCellMetaInfoOp (ci, name_id, from, &i));
}
m_meta_info_by_cell[ci][name_id] = i; m_meta_info_by_cell[ci][name_id] = i;
} }
@ -1914,6 +2044,18 @@ void
Layout::remove_meta_info (db::cell_index_type ci, meta_info_name_id_type name_id) Layout::remove_meta_info (db::cell_index_type ci, meta_info_name_id_type name_id)
{ {
auto c = m_meta_info_by_cell.find (ci); auto c = m_meta_info_by_cell.find (ci);
if (manager () && manager ()->transacting ()) {
const MetaInfo *from = 0;
if (c != m_meta_info_by_cell.end ()) {
auto e = c->second.find (name_id);
if (e != c->second.end ()) {
from = &e->second;
}
}
manager ()->queue (this, new SetCellMetaInfoOp (ci, name_id, from, 0));
}
if (c != m_meta_info_by_cell.end ()) { if (c != m_meta_info_by_cell.end ()) {
c->second.erase (name_id); c->second.erase (name_id);
} }
@ -1945,6 +2087,40 @@ Layout::has_meta_info (db::cell_index_type ci, meta_info_name_id_type name_id) c
} }
} }
void
Layout::merge_meta_info (const db::Layout &other)
{
for (auto mi = other.begin_meta (); mi != other.end_meta (); ++mi) {
add_meta_info (other.meta_info_name (mi->first), mi->second);
}
}
void
Layout::merge_meta_info (db::cell_index_type into_cell, const db::Layout &other, db::cell_index_type other_cell)
{
auto mi_begin = other.begin_meta (other_cell);
auto mi_end = other.end_meta (other_cell);
for (auto mi = mi_begin; mi != mi_end; ++mi) {
add_meta_info (into_cell, other.meta_info_name (mi->first), mi->second);
}
}
void
Layout::merge_meta_info (const db::Layout &other, const db::CellMapping &cm)
{
for (auto i = cm.begin (); i != cm.end (); ++i) {
merge_meta_info (i->second, other, i->first);
}
}
void
Layout::copy_meta_info (const db::Layout &other, const db::CellMapping &cm)
{
for (auto i = cm.begin (); i != cm.end (); ++i) {
copy_meta_info (i->second, other, i->first);
}
}
void void
Layout::swap_layers (unsigned int a, unsigned int b) Layout::swap_layers (unsigned int a, unsigned int b)
{ {

View File

@ -1993,6 +1993,11 @@ public:
*/ */
void clear_meta (db::cell_index_type ci); void clear_meta (db::cell_index_type ci);
/**
* @brief Clears all meta information (cells and layout)
*/
void clear_all_meta ();
/** /**
* @brief Adds meta information for a given cell * @brief Adds meta information for a given cell
* The given meta information object is to the meta information list for the given cell. * The given meta information object is to the meta information list for the given cell.
@ -2021,6 +2026,50 @@ public:
} }
} }
/**
* @brief Merges meta information from the other layout into self
* This applies to the layout-only meta information. Same keys get overwritten, new ones are added.
*/
void merge_meta_info (const db::Layout &other);
/**
* @brief Copies meta information from the other layout into self
* This applies to the layout-only meta information. All keys are replaced.
*/
void copy_meta_info (const db::Layout &other)
{
clear_meta ();
merge_meta_info (other);
}
/**
* @brief Merges meta information from the other cell into the target cell from sel.
* This applies to the cell-specific meta information. Same keys get overwritten, new ones are added.
*/
void merge_meta_info (db::cell_index_type into_cell, const db::Layout &other, db::cell_index_type other_cell);
/**
* @brief Copies meta information from the other cell into the target cell from sel.
* This applies to the cell-specific meta information. All keys are replaced.
*/
void copy_meta_info (db::cell_index_type into_cell, const db::Layout &other, db::cell_index_type other_cell)
{
clear_meta (into_cell);
merge_meta_info (into_cell, other, other_cell);
}
/**
* @brief Merges meta information from the other cell into the target cell from sel using the given cell mapping.
* The cell mapping specifies which meta information to merge from which cell into which cell.
*/
void merge_meta_info (const db::Layout &other, const db::CellMapping &cm);
/**
* @brief Copies meta information from the other cell into the target cell from sel using the given cell mapping.
* The cell mapping specifies which meta information to copy from which cell into which cell.
*/
void copy_meta_info (const db::Layout &other, const db::CellMapping &cm);
/** /**
* @brief Gets a value indicating whether a meta info with the given name is present for the given cell * @brief Gets a value indicating whether a meta info with the given name is present for the given cell
*/ */

View File

@ -702,6 +702,29 @@ do_compare_layouts (const db::Layout &a, const db::Cell *top_a, const db::Layout
r.dbu_differs (a.dbu (), b.dbu ()); r.dbu_differs (a.dbu (), b.dbu ());
} }
if ((flags & layout_diff::f_with_meta) != 0) {
std::map<std::string, std::pair<tl::Variant, tl::Variant> > mi;
for (auto i = a.begin_meta (); i != a.end_meta (); ++i) {
if (i->second.persisted) {
mi [a.meta_info_name (i->first)].first = i->second.value;
}
}
for (auto i = b.begin_meta (); i != b.end_meta (); ++i) {
if (i->second.persisted) {
mi [b.meta_info_name (i->first)].second = i->second.value;
}
}
for (auto i = mi.begin (); i != mi.end (); ++i) {
if (i->second.first != i->second.second) {
differs = true;
if (flags & layout_diff::f_silent) {
return false;
}
r.layout_meta_info_differs (i->first, i->second.first, i->second.second);
}
}
}
bool verbose = (flags & layout_diff::f_verbose); bool verbose = (flags & layout_diff::f_verbose);
bool no_duplicates = (flags & layout_diff::f_ignore_duplicates); bool no_duplicates = (flags & layout_diff::f_ignore_duplicates);
@ -928,6 +951,33 @@ do_compare_layouts (const db::Layout &a, const db::Cell *top_a, const db::Layout
r.begin_cell (common_cells [cci], common_cells_a [cci], common_cells_b [cci]); r.begin_cell (common_cells [cci], common_cells_a [cci], common_cells_b [cci]);
if ((flags & layout_diff::f_with_meta) != 0) {
std::map<std::string, std::pair<tl::Variant, tl::Variant> > mi;
auto ib = a.begin_meta (common_cells_a [cci]);
auto ie = a.end_meta (common_cells_a [cci]);
for (auto i = ib; i != ie; ++i) {
if (i->second.persisted) {
mi [a.meta_info_name (i->first)].first = i->second.value;
}
}
ib = b.begin_meta (common_cells_b [cci]);
ie = b.end_meta (common_cells_b [cci]);
for (auto i = ib; i != ie; ++i) {
if (i->second.persisted) {
mi [b.meta_info_name (i->first)].second = i->second.value;
}
}
for (auto i = mi.begin (); i != mi.end (); ++i) {
if (i->second.first != i->second.second) {
differs = true;
if (flags & layout_diff::f_silent) {
return false;
}
r.cell_meta_info_differs (i->first, i->second.first, i->second.second);
}
}
}
if (!verbose && cell_a->bbox () != cell_b->bbox ()) { if (!verbose && cell_a->bbox () != cell_b->bbox ()) {
differs = true; differs = true;
if (flags & layout_diff::f_silent) { if (flags & layout_diff::f_silent) {
@ -1215,6 +1265,7 @@ public:
} }
void dbu_differs (double dbu_a, double dbu_b); void dbu_differs (double dbu_a, double dbu_b);
void layout_meta_info_differs (const std::string &name, const tl::Variant &a, const tl::Variant &b);
void layer_in_a_only (const db::LayerProperties &la); void layer_in_a_only (const db::LayerProperties &la);
void layer_in_b_only (const db::LayerProperties &lb); void layer_in_b_only (const db::LayerProperties &lb);
void layer_name_differs (const db::LayerProperties &la, const db::LayerProperties &lb); void layer_name_differs (const db::LayerProperties &la, const db::LayerProperties &lb);
@ -1222,6 +1273,7 @@ public:
void cell_in_b_only (const std::string &cellname, db::cell_index_type ci); void cell_in_b_only (const std::string &cellname, db::cell_index_type ci);
void cell_name_differs (const std::string &cellname_a, db::cell_index_type cia, const std::string &cellname_b, db::cell_index_type cib); void cell_name_differs (const std::string &cellname_a, db::cell_index_type cia, const std::string &cellname_b, db::cell_index_type cib);
void begin_cell (const std::string &cellname, db::cell_index_type cia, db::cell_index_type cib); void begin_cell (const std::string &cellname, db::cell_index_type cia, db::cell_index_type cib);
void cell_meta_info_differs (const std::string &name, const tl::Variant &a, const tl::Variant &b);
void bbox_differs (const db::Box &ba, const db::Box &bb); void bbox_differs (const db::Box &ba, const db::Box &bb);
void begin_inst_differences (); void begin_inst_differences ();
void instances_in_a (const std::vector <db::CellInstArrayWithProperties> &insts_a, const std::vector <std::string> &cell_names, const db::PropertiesRepository &props); void instances_in_a (const std::vector <db::CellInstArrayWithProperties> &insts_a, const std::vector <std::string> &cell_names, const db::PropertiesRepository &props);
@ -1384,6 +1436,16 @@ PrintingDifferenceReceiver::dbu_differs (double dbu_a, double dbu_b)
} }
} }
void
PrintingDifferenceReceiver::layout_meta_info_differs (const std::string &name, const tl::Variant &a, const tl::Variant &b)
{
try {
enough (tl::error) << "Global meta info differs - [" << name << "]: " << a << " vs. " << b;
} catch (tl::CancelException &) {
// ignore cancel exceptions
}
}
void void
PrintingDifferenceReceiver::layer_in_a_only (const db::LayerProperties &la) PrintingDifferenceReceiver::layer_in_a_only (const db::LayerProperties &la)
{ {
@ -1461,6 +1523,16 @@ PrintingDifferenceReceiver::begin_cell (const std::string &cellname, db::cell_in
m_cellname = cellname; m_cellname = cellname;
} }
void
PrintingDifferenceReceiver::cell_meta_info_differs (const std::string &name, const tl::Variant &a, const tl::Variant &b)
{
try {
enough (tl::error) << "Meta info differs in cell " << m_cellname << " - [" << name << "]: " << a << " vs. " << b;
} catch (tl::CancelException &) {
// ignore cancel exceptions
}
}
void void
PrintingDifferenceReceiver::begin_inst_differences () PrintingDifferenceReceiver::begin_inst_differences ()
{ {

View File

@ -56,6 +56,9 @@ const unsigned int f_no_text_orientation = 0x02;
// Ignore properties // Ignore properties
const unsigned int f_no_properties = 0x04; const unsigned int f_no_properties = 0x04;
// With meta info
const unsigned int f_with_meta = 0x08;
// Do not compare layer names // Do not compare layer names
const unsigned int f_no_layer_names = 0x10; const unsigned int f_no_layer_names = 0x10;
@ -94,6 +97,7 @@ public:
virtual ~DifferenceReceiver () { } virtual ~DifferenceReceiver () { }
virtual void dbu_differs (double /*dbu_a*/, double /*dbu_b*/) { } virtual void dbu_differs (double /*dbu_a*/, double /*dbu_b*/) { }
virtual void layout_meta_info_differs (const std::string & /*name*/, const tl::Variant & /*value_a*/, const tl::Variant & /*value_b*/) { }
virtual void layer_in_a_only (const db::LayerProperties & /*la*/) { } virtual void layer_in_a_only (const db::LayerProperties & /*la*/) { }
virtual void layer_in_b_only (const db::LayerProperties & /*lb*/) { } virtual void layer_in_b_only (const db::LayerProperties & /*lb*/) { }
virtual void layer_name_differs (const db::LayerProperties & /*la*/, const db::LayerProperties & /*lb*/) { } virtual void layer_name_differs (const db::LayerProperties & /*la*/, const db::LayerProperties & /*lb*/) { }
@ -102,6 +106,7 @@ public:
virtual void cell_in_b_only (const std::string & /*cellname*/, db::cell_index_type /*ci*/) { } virtual void cell_in_b_only (const std::string & /*cellname*/, db::cell_index_type /*ci*/) { }
virtual void bbox_differs (const db::Box & /*ba*/, const db::Box & /*bb*/) { } virtual void bbox_differs (const db::Box & /*ba*/, const db::Box & /*bb*/) { }
virtual void begin_cell (const std::string & /*cellname*/, db::cell_index_type /*cia*/, db::cell_index_type /*cib*/) { } virtual void begin_cell (const std::string & /*cellname*/, db::cell_index_type /*cia*/, db::cell_index_type /*cib*/) { }
virtual void cell_meta_info_differs (const std::string & /*name*/, const tl::Variant & /*value_a*/, const tl::Variant & /*value_b*/) { }
virtual void begin_inst_differences () { } virtual void begin_inst_differences () { }
virtual void instances_in_a (const std::vector <db::CellInstArrayWithProperties> & /*insts_a*/, const std::vector <std::string> & /*cell_names*/, const db::PropertiesRepository & /*props*/) { } virtual void instances_in_a (const std::vector <db::CellInstArrayWithProperties> & /*insts_a*/, const std::vector <std::string> & /*cell_names*/, const db::PropertiesRepository & /*props*/) { }
virtual void instances_in_b (const std::vector <db::CellInstArrayWithProperties> & /*insts_b*/, const std::vector <std::string> & /*cell_names*/, const db::PropertiesRepository & /*props*/) { } virtual void instances_in_b (const std::vector <db::CellInstArrayWithProperties> & /*insts_b*/, const std::vector <std::string> & /*cell_names*/, const db::PropertiesRepository & /*props*/) { }

View File

@ -252,6 +252,9 @@ merge_layouts (db::Layout &target,
const db::Cell &source_cell = source.cell (*c); const db::Cell &source_cell = source.cell (*c);
db::Cell &target_cell = target.cell (target_cell_index); db::Cell &target_cell = target.cell (target_cell_index);
// merge meta info
target.merge_meta_info (target_cell_index, source, *c);
// NOTE: this implementation employs the safe but cumbersome "local transformation" feature. // NOTE: this implementation employs the safe but cumbersome "local transformation" feature.
// This means, all cells are transformed according to the given transformation and their // This means, all cells are transformed according to the given transformation and their
// references are transformed to account for that effect. This will lead to somewhat strange // references are transformed to account for that effect. This will lead to somewhat strange

View File

@ -287,19 +287,37 @@ void NetlistDeviceExtractor::extract_without_initialize (db::Layout &layout, db:
extractor_cache_type::const_iterator ec = extractor_cache.find (layer_geometry); extractor_cache_type::const_iterator ec = extractor_cache.find (layer_geometry);
if (ec == extractor_cache.end ()) { if (ec == extractor_cache.end ()) {
log_entry_list log_entries;
m_log_entries.swap (log_entries);
// do the actual device extraction // do the actual device extraction
extract_devices (layer_geometry); extract_devices (layer_geometry);
// push the new devices to the layout // push the new devices to the layout
push_new_devices (disp); push_new_devices (disp);
ExtractorCacheValueType &ecv = extractor_cache [layer_geometry]; if (m_log_entries.empty ()) {
ecv.disp = disp;
// cache unless log entries are produced
ExtractorCacheValueType &ecv = extractor_cache [layer_geometry];
ecv.disp = disp;
for (std::map<size_t, std::pair<db::Device *, geometry_per_terminal_type> >::const_iterator d = m_new_devices.begin (); d != m_new_devices.end (); ++d) {
ecv.devices.push_back (d->second.first);
}
} else {
// transform the marker geometries from the log entries to match the device
db::DVector disp_dbu = db::CplxTrans (dbu ()) * disp;
for (auto l = m_log_entries.begin (); l != m_log_entries.end (); ++l) {
l->set_geometry (l->geometry ().moved (disp_dbu));
}
for (std::map<size_t, std::pair<db::Device *, geometry_per_terminal_type> >::const_iterator d = m_new_devices.begin (); d != m_new_devices.end (); ++d) {
ecv.devices.push_back (d->second.first);
} }
m_log_entries.splice (m_log_entries.begin (), log_entries);
m_new_devices.clear (); m_new_devices.clear ();
} else { } else {

View File

@ -139,6 +139,7 @@ void compare_layouts (tl::TestBase *_this, const db::Layout &layout, const std::
(n > 0 ? db::layout_diff::f_silent : db::layout_diff::f_verbose) (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) | ((norm & AsPolygons) != 0 ? db::layout_diff::f_boxes_as_polygons + db::layout_diff::f_paths_as_polygons : 0)
| ((norm & WithArrays) != 0 ? 0 : db::layout_diff::f_flatten_array_insts) | ((norm & WithArrays) != 0 ? 0 : db::layout_diff::f_flatten_array_insts)
| ((norm & WithMeta) == 0 ? 0 : db::layout_diff::f_with_meta)
/*| db::layout_diff::f_no_text_details | db::layout_diff::f_no_text_orientation*/ /*| db::layout_diff::f_no_text_details | db::layout_diff::f_no_text_orientation*/
, tolerance, 100 /*max diff lines*/); , tolerance, 100 /*max diff lines*/);
if (equal && n > 0) { if (equal && n > 0) {

View File

@ -58,7 +58,8 @@ enum NormalizationMode
NormFileMask = 7, // bits the extract for file mode NormFileMask = 7, // bits the extract for file mode
NoContext = 8, // write tmp file without context 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 WithArrays = 32, // do not flatten arrays
WithMeta = 64 // with meta info
}; };
/** /**

View File

@ -1004,6 +1004,22 @@ static void cell_add_meta_info (db::Cell *cell, const MetaInfo &mi)
} }
} }
static void cell_merge_meta_info (db::Cell *cell, const db::Cell *source)
{
if (! source || ! cell->layout () || ! source->layout ()) {
return;
}
cell->layout ()->merge_meta_info (cell->cell_index (), *source->layout (), source->cell_index ());
}
static void cell_copy_meta_info (db::Cell *cell, const db::Cell *source)
{
if (! source || ! cell->layout () || ! source->layout ()) {
return;
}
cell->layout ()->copy_meta_info (cell->cell_index (), *source->layout (), source->cell_index ());
}
static const tl::Variant &cell_meta_info_value (db::Cell *cell, const std::string &name) static const tl::Variant &cell_meta_info_value (db::Cell *cell, const std::string &name)
{ {
if (! cell->layout ()) { if (! cell->layout ()) {
@ -1755,6 +1771,7 @@ read_options (db::Cell *cell, const std::string &path, const db::LoadLayoutOptio
db::CellMapping cm; db::CellMapping cm;
std::vector<db::cell_index_type> new_cells = cm.create_single_mapping_full (*cell->layout (), cell->cell_index (), tmp, *tmp.begin_top_down ()); std::vector<db::cell_index_type> new_cells = cm.create_single_mapping_full (*cell->layout (), cell->cell_index (), tmp, *tmp.begin_top_down ());
cell->move_tree_shapes (tmp.cell (*tmp.begin_top_down ()), cm); cell->move_tree_shapes (tmp.cell (*tmp.begin_top_down ()), cm);
cell->layout ()->merge_meta_info (tmp, cm);
return new_cells; return new_cells;
} }
@ -1834,6 +1851,21 @@ Class<db::Cell> decl_Cell ("db", "Cell",
"\n" "\n"
"This method has been introduced in version 0.28.8." "This method has been introduced in version 0.28.8."
) + ) +
gsi::method_ext ("merge_meta_info", &cell_merge_meta_info, gsi::arg ("other"),
"@brief Merges the meta information from the other cell into this cell\n"
"See \\LayoutMetaInfo for details about cells and meta information.\n"
"Existing keys in this cell will be overwritten by the respective values from the other cell.\n"
"New keys will be added.\n"
"\n"
"This method has been introduced in version 0.28.16."
) +
gsi::method_ext ("copy_meta_info", &cell_copy_meta_info, gsi::arg ("other"),
"@brief Copies the meta information from the other cell into this cell\n"
"See \\LayoutMetaInfo for details about cells and meta information.\n"
"The meta information from this cell will be replaced by the meta information from the other cell.\n"
"\n"
"This method has been introduced in version 0.28.16."
) +
gsi::method_ext ("clear_meta_info", &cell_clear_meta_info, gsi::method_ext ("clear_meta_info", &cell_clear_meta_info,
"@brief Clears the meta information of the cell\n" "@brief Clears the meta information of the cell\n"
"See \\LayoutMetaInfo for details about cells and meta information.\n" "See \\LayoutMetaInfo for details about cells and meta information.\n"

View File

@ -1105,12 +1105,54 @@ Class<db::Layout> decl_Layout ("db", "Layout",
"\n" "\n"
"This method has been introduced in version 0.25." "This method has been introduced in version 0.25."
) + ) +
gsi::method ("merge_meta_info", static_cast<void (db::Layout::*) (const db::Layout &)> (&db::Layout::merge_meta_info), gsi::arg ("other"),
"@brief Merges the meta information from the other layout into this layout\n"
"See \\LayoutMetaInfo for details about cells and meta information.\n"
"Existing keys in this layout will be overwritten by the respective values from the other layout.\n"
"New keys will be added.\n"
"\n"
"This method has been introduced in version 0.28.16."
) +
gsi::method ("merge_meta_info", static_cast<void (db::Layout::*) (const db::Layout &, const db::CellMapping &cm)> (&db::Layout::merge_meta_info), gsi::arg ("other"), gsi::arg ("cm"),
"@brief Merges the meta information from the other layout into this layout for the cells given by the cell mapping\n"
"See \\LayoutMetaInfo for details about cells and meta information.\n"
"This method will use the source/target cell pairs from the cell mapping object and merge the meta information "
"from each source cell from the 'other' layout into the mapped cell inside self.\n"
"This method can be used with '\\copy_tree_shapes' and similar to copy meta information in addition to the shapes.\n"
"Existing cell-specific keys in this layout will be overwritten by the respective values from the other layout.\n"
"New keys will be added.\n"
"\n"
"This method has been introduced in version 0.28.16."
) +
gsi::method ("copy_meta_info", static_cast<void (db::Layout::*) (const db::Layout &)> (&db::Layout::copy_meta_info), gsi::arg ("other"),
"@brief Copies the meta information from the other layout into this layout\n"
"See \\LayoutMetaInfo for details about cells and meta information.\n"
"The meta information from this layout will be replaced by the meta information from the other layout.\n"
"\n"
"This method has been introduced in version 0.28.16."
) +
gsi::method ("copy_meta_info", static_cast<void (db::Layout::*) (const db::Layout &, const db::CellMapping &cm)> (&db::Layout::copy_meta_info), gsi::arg ("other"), gsi::arg ("cm"),
"@brief Copies the meta information from the other layout into this layout for the cells given by the cell mapping\n"
"See \\LayoutMetaInfo for details about cells and meta information.\n"
"This method will use the source/target cell pairs from the cell mapping object and merge the meta information "
"from each source cell from the 'other' layout into the mapped cell inside self.\n"
"This method can be used with '\\copy_tree_shapes' and similar to copy meta information in addition to the shapes.\n"
"All cell-specific keys in this layout will be replaced by the respective values from the other layout.\n"
"\n"
"This method has been introduced in version 0.28.16."
) +
gsi::method ("clear_meta_info", static_cast<void (db::Layout::*) ()> (&db::Layout::clear_meta), gsi::method ("clear_meta_info", static_cast<void (db::Layout::*) ()> (&db::Layout::clear_meta),
"@brief Clears the meta information of the layout\n" "@brief Clears the meta information of the layout\n"
"See \\LayoutMetaInfo for details about layouts and meta information." "See \\LayoutMetaInfo for details about layouts and meta information."
"\n" "\n"
"This method has been introduced in version 0.28.8." "This method has been introduced in version 0.28.8."
) + ) +
gsi::method ("clear_all_meta_info", static_cast<void (db::Layout::*) ()> (&db::Layout::clear_all_meta),
"@brief Clears all meta information of the layout (cell specific and global)\n"
"See \\LayoutMetaInfo for details about layouts and meta information."
"\n"
"This method has been introduced in version 0.28.16."
) +
gsi::method ("remove_meta_info", static_cast<void (db::Layout::*) (const std::string &name)> (&db::Layout::remove_meta_info), gsi::arg ("name"), gsi::method ("remove_meta_info", static_cast<void (db::Layout::*) (const std::string &name)> (&db::Layout::remove_meta_info), gsi::arg ("name"),
"@brief Removes meta information from the layout\n" "@brief Removes meta information from the layout\n"
"See \\LayoutMetaInfo for details about layouts and meta information." "See \\LayoutMetaInfo for details about layouts and meta information."

View File

@ -90,6 +90,11 @@ public:
dbu_differs_event (dbu_a, dbu_b); dbu_differs_event (dbu_a, dbu_b);
} }
virtual void layout_meta_info_differs (const std::string &name, const tl::Variant &value_a, const tl::Variant &value_b)
{
layout_meta_info_differs_event (name, value_a, value_b);
}
virtual void layer_in_a_only (const db::LayerProperties &la) virtual void layer_in_a_only (const db::LayerProperties &la)
{ {
layer_in_a_only_event (la); layer_in_a_only_event (la);
@ -132,6 +137,11 @@ public:
begin_cell_event (mp_cell_a, mp_cell_b); begin_cell_event (mp_cell_a, mp_cell_b);
} }
virtual void cell_meta_info_differs (const std::string &name, const tl::Variant &value_a, const tl::Variant &value_b)
{
cell_meta_info_differs_event (name, value_a, value_b);
}
virtual void begin_inst_differences () virtual void begin_inst_differences ()
{ {
begin_inst_differences_event (); begin_inst_differences_event ();
@ -343,6 +353,7 @@ public:
} }
tl::event<double /*dbu_a*/, double /*dbu_a*/> dbu_differs_event; tl::event<double /*dbu_a*/, double /*dbu_a*/> dbu_differs_event;
tl::event<const std::string & /*name*/, const tl::Variant & /*value_a*/, const tl::Variant & /*value_b*/> layout_meta_info_differs_event;
tl::event<const db::LayerProperties & /*a*/> layer_in_a_only_event; tl::event<const db::LayerProperties & /*a*/> layer_in_a_only_event;
tl::event<const db::LayerProperties & /*b*/> layer_in_b_only_event; tl::event<const db::LayerProperties & /*b*/> layer_in_b_only_event;
tl::event<const db::LayerProperties & /*a*/, const db::LayerProperties & /*b*/> layer_name_differs_event; tl::event<const db::LayerProperties & /*a*/, const db::LayerProperties & /*b*/> layer_name_differs_event;
@ -351,6 +362,7 @@ public:
tl::event<const db::Cell * /*c*/> cell_in_b_only_event; tl::event<const db::Cell * /*c*/> cell_in_b_only_event;
tl::event<const db::Box & /*ba*/, const db::Box & /*bb*/> bbox_differs_event; tl::event<const db::Box & /*ba*/, const db::Box & /*bb*/> bbox_differs_event;
tl::event<const db::Cell * /*ca*/, const db::Cell * /*cb*/> begin_cell_event; tl::event<const db::Cell * /*ca*/, const db::Cell * /*cb*/> begin_cell_event;
tl::event<const std::string & /*name*/, const tl::Variant & /*value_a*/, const tl::Variant & /*value_b*/> cell_meta_info_differs_event;
tl::Event begin_inst_differences_event; tl::Event begin_inst_differences_event;
tl::event<const db::CellInstArray & /*anotb*/, db::properties_id_type /*prop_id*/> instance_in_a_only_event; tl::event<const db::CellInstArray & /*anotb*/, db::properties_id_type /*prop_id*/> instance_in_a_only_event;
tl::event<const db::CellInstArray & /*bnota*/, db::properties_id_type /*prop_id*/> instance_in_b_only_event; tl::event<const db::CellInstArray & /*bnota*/, db::properties_id_type /*prop_id*/> instance_in_b_only_event;
@ -409,6 +421,10 @@ static unsigned int f_no_properties () {
return db::layout_diff::f_no_properties; return db::layout_diff::f_no_properties;
} }
static unsigned int f_with_meta () {
return db::layout_diff::f_with_meta;
}
static unsigned int f_no_layer_names () { static unsigned int f_no_layer_names () {
return db::layout_diff::f_no_layer_names; return db::layout_diff::f_no_layer_names;
} }
@ -450,7 +466,7 @@ gsi::Class<LayoutDiff> decl_LayoutDiff ("db", "LayoutDiff",
"full compare.\n" "full compare.\n"
"\n" "\n"
"This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be " "This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be "
"compared with other constants to form a flag set." "combined with other constants to form a flag set."
) + ) +
gsi::constant ("IgnoreDuplicates", &f_ignore_duplicates, gsi::constant ("IgnoreDuplicates", &f_ignore_duplicates,
"@brief Ignore duplicate instances or shapes\n" "@brief Ignore duplicate instances or shapes\n"
@ -462,17 +478,25 @@ gsi::Class<LayoutDiff> decl_LayoutDiff ("db", "LayoutDiff",
gsi::constant ("NoTextOrientation", &f_no_text_orientation, gsi::constant ("NoTextOrientation", &f_no_text_orientation,
"@brief Ignore text orientation\n" "@brief Ignore text orientation\n"
"This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be " "This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be "
"compared with other constants to form a flag set." "combined with other constants to form a flag set."
) + ) +
gsi::constant ("NoProperties", &f_no_properties, gsi::constant ("NoProperties", &f_no_properties,
"@brief Ignore properties\n" "@brief Ignore properties\n"
"This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be " "This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be "
"compared with other constants to form a flag set." "combined with other constants to form a flag set."
) +
gsi::constant ("WithMetaInfo", &f_with_meta,
"@brief Ignore meta info\n"
"This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be "
"combined with other constants to form a flag set. If present, this option tells the compare algorithm "
"to include persisted meta info in the compare.\n"
"\n"
"This flag has been introduced in version 0.28.16."
) + ) +
gsi::constant ("NoLayerNames", &f_no_layer_names, gsi::constant ("NoLayerNames", &f_no_layer_names,
"@brief Do not compare layer names\n" "@brief Do not compare layer names\n"
"This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be " "This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be "
"compared with other constants to form a flag set." "combined with other constants to form a flag set."
) + ) +
gsi::constant ("Verbose", &f_verbose, gsi::constant ("Verbose", &f_verbose,
"@brief Enables verbose mode (gives details about the differences)\n" "@brief Enables verbose mode (gives details about the differences)\n"
@ -480,22 +504,22 @@ gsi::Class<LayoutDiff> decl_LayoutDiff ("db", "LayoutDiff",
"See the event descriptions for details about the differences in verbose and non-verbose mode.\n" "See the event descriptions for details about the differences in verbose and non-verbose mode.\n"
"\n" "\n"
"This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be " "This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be "
"compared with other constants to form a flag set." "combined with other constants to form a flag set."
) + ) +
gsi::constant ("BoxesAsPolygons", &f_boxes_as_polygons, gsi::constant ("BoxesAsPolygons", &f_boxes_as_polygons,
"@brief Compare boxes to polygons\n" "@brief Compare boxes to polygons\n"
"This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be " "This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be "
"compared with other constants to form a flag set." "combined with other constants to form a flag set."
) + ) +
gsi::constant ("FlattenArrayInsts", &f_flatten_array_insts, gsi::constant ("FlattenArrayInsts", &f_flatten_array_insts,
"@brief Compare array instances instance by instance\n" "@brief Compare array instances instance by instance\n"
"This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be " "This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be "
"compared with other constants to form a flag set." "combined with other constants to form a flag set."
) + ) +
gsi::constant ("PathsAsPolygons", &f_paths_as_polygons, gsi::constant ("PathsAsPolygons", &f_paths_as_polygons,
"@brief Compare paths to polygons\n" "@brief Compare paths to polygons\n"
"This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be " "This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be "
"compared with other constants to form a flag set." "combined with other constants to form a flag set."
) + ) +
gsi::constant ("SmartCellMapping", &f_smart_cell_mapping, gsi::constant ("SmartCellMapping", &f_smart_cell_mapping,
"@brief Derive smart cell mapping instead of name mapping (available only if top cells are specified)\n" "@brief Derive smart cell mapping instead of name mapping (available only if top cells are specified)\n"
@ -503,7 +527,7 @@ gsi::Class<LayoutDiff> decl_LayoutDiff ("db", "LayoutDiff",
"cells are compared (with \\LayoutDiff#compare with cells instead of layout objects).\n" "cells are compared (with \\LayoutDiff#compare with cells instead of layout objects).\n"
"\n" "\n"
"This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be " "This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be "
"compared with other constants to form a flag set.\n" "combined with other constants to form a flag set.\n"
) + ) +
gsi::constant ("DontSummarizeMissingLayers", &f_dont_summarize_missing_layers, gsi::constant ("DontSummarizeMissingLayers", &f_dont_summarize_missing_layers,
"@brief Don't summarize missing layers\n" "@brief Don't summarize missing layers\n"
@ -511,12 +535,12 @@ gsi::Class<LayoutDiff> decl_LayoutDiff ("db", "LayoutDiff",
"layer will be reported as difference.\n" "layer will be reported as difference.\n"
"\n" "\n"
"This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be " "This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be "
"compared with other constants to form a flag set." "combined with other constants to form a flag set."
) + ) +
gsi::constant ("NoTextDetails", &f_no_text_details, gsi::constant ("NoTextDetails", &f_no_text_details,
"@brief Ignore text details (font, size, presentation)\n" "@brief Ignore text details (font, size, presentation)\n"
"This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be " "This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be "
"compared with other constants to form a flag set." "combined with other constants to form a flag set."
) + ) +
gsi::method ("compare", &LayoutDiff::compare_layouts, gsi::method ("compare", &LayoutDiff::compare_layouts,
gsi::arg("a"), gsi::arg("a"),
@ -593,6 +617,14 @@ gsi::Class<LayoutDiff> decl_LayoutDiff ("db", "LayoutDiff",
gsi::event ("on_dbu_differs", &LayoutDiff::dbu_differs_event, gsi::arg ("dbu_a"), gsi::arg ("dbu_b"), gsi::event ("on_dbu_differs", &LayoutDiff::dbu_differs_event, gsi::arg ("dbu_a"), gsi::arg ("dbu_b"),
"@brief This signal indicates a difference in the database units of the layouts\n" "@brief This signal indicates a difference in the database units of the layouts\n"
) + ) +
gsi::event ("on_layout_meta_info_differs", &LayoutDiff::layout_meta_info_differs_event, gsi::arg ("name"), gsi::arg ("a"), gsi::arg ("b"),
"@brief This signal indicates that global meta info differs\n"
"Meta information is only compared when \\WithMetaInfo is added to the compare flags.\n"
"'a' and 'b' are the values for the first and second layout. 'nil' is passed to these values to indicate "
"missing meta information on one side.\n"
"\n"
"This event has been added in version 0.28.16."
) +
gsi::event ("on_layer_in_a_only", &LayoutDiff::layer_in_a_only_event, gsi::arg ("a"), gsi::event ("on_layer_in_a_only", &LayoutDiff::layer_in_a_only_event, gsi::arg ("a"),
"@brief This signal indicates a layer that is present only in the first layout\n" "@brief This signal indicates a layer that is present only in the first layout\n"
) + ) +
@ -619,9 +651,17 @@ gsi::Class<LayoutDiff> decl_LayoutDiff ("db", "LayoutDiff",
"In verbose mode detailed events will be issued indicating the differences.\n" "In verbose mode detailed events will be issued indicating the differences.\n"
) + ) +
gsi::event ("on_begin_cell", &LayoutDiff::begin_cell_event, gsi::arg ("ca"), gsi::arg ("cb"), gsi::event ("on_begin_cell", &LayoutDiff::begin_cell_event, gsi::arg ("ca"), gsi::arg ("cb"),
"@brief This signal initiates the sequence of events for a cell pair\n" "@brief This signal indicates the sequence of events for a cell pair\n"
"All cell specific events happen between \\begin_cell_event and \\end_cell_event signals." "All cell specific events happen between \\begin_cell_event and \\end_cell_event signals."
) + ) +
gsi::event ("on_cell_meta_info_differs", &LayoutDiff::cell_meta_info_differs_event, gsi::arg ("name"), gsi::arg ("a"), gsi::arg ("b"),
"@brief This signal indicates that meta info between the current cells differs\n"
"Meta information is only compared when \\WithMetaInfo is added to the compare flags.\n"
"'a' and 'b' are the values for the first and second layout. 'nil' is passed to these values to indicate "
"missing meta information on one side.\n"
"\n"
"This event has been added in version 0.28.16."
) +
gsi::event ("on_begin_inst_differences", &LayoutDiff::begin_inst_differences_event, gsi::event ("on_begin_inst_differences", &LayoutDiff::begin_inst_differences_event,
"@brief This signal indicates differences in the cell instances\n" "@brief This signal indicates differences in the cell instances\n"
"In verbose mode (see \\Verbose) more events will follow that indicate the instances that are present only " "In verbose mode (see \\Verbose) more events will follow that indicate the instances that are present only "

View File

@ -38,6 +38,7 @@ public:
std::string text () const { return m_os.str (); } std::string text () const { return m_os.str (); }
void clear () { m_os.str (std::string ()); } void clear () { m_os.str (std::string ()); }
void dbu_differs (double dbu_a, double dbu_b); void dbu_differs (double dbu_a, double dbu_b);
void layout_meta_info_differs (const std::string &, const tl::Variant &, const tl::Variant &);
void layer_in_a_only (const db::LayerProperties &la); void layer_in_a_only (const db::LayerProperties &la);
void layer_in_b_only (const db::LayerProperties &lb); void layer_in_b_only (const db::LayerProperties &lb);
void layer_name_differs (const db::LayerProperties &la, const db::LayerProperties &lb); void layer_name_differs (const db::LayerProperties &la, const db::LayerProperties &lb);
@ -45,6 +46,7 @@ public:
void cell_in_b_only (const std::string &cellname, db::cell_index_type ci); void cell_in_b_only (const std::string &cellname, db::cell_index_type ci);
void cell_name_differs (const std::string &cellname_a, db::cell_index_type cia, const std::string &cellname_b, db::cell_index_type cib); void cell_name_differs (const std::string &cellname_a, db::cell_index_type cia, const std::string &cellname_b, db::cell_index_type cib);
void begin_cell (const std::string &cellname, db::cell_index_type cia, db::cell_index_type cib); void begin_cell (const std::string &cellname, db::cell_index_type cia, db::cell_index_type cib);
void cell_meta_info_differs (const std::string &, const tl::Variant &, const tl::Variant &);
void bbox_differs (const db::Box &ba, const db::Box &bb); void bbox_differs (const db::Box &ba, const db::Box &bb);
void begin_inst_differences (); void begin_inst_differences ();
void instances_in_a (const std::vector <db::CellInstArrayWithProperties> &insts_a, const std::vector <std::string> &cell_names, const db::PropertiesRepository &props); void instances_in_a (const std::vector <db::CellInstArrayWithProperties> &insts_a, const std::vector <std::string> &cell_names, const db::PropertiesRepository &props);
@ -155,6 +157,12 @@ TestDifferenceReceiver::dbu_differs (double dbu_a, double dbu_b)
m_os << "layout_diff: database units differ " << dbu_a << " vs. " << dbu_b << std::endl; m_os << "layout_diff: database units differ " << dbu_a << " vs. " << dbu_b << std::endl;
} }
void
TestDifferenceReceiver::layout_meta_info_differs (const std::string &name, const tl::Variant &va, const tl::Variant &vb)
{
m_os << "layout_diff: global meta info differs " << name << ": " << va.to_string () << " vs. " << vb.to_string () << std::endl;
}
void void
TestDifferenceReceiver::layer_in_a_only (const db::LayerProperties &la) TestDifferenceReceiver::layer_in_a_only (const db::LayerProperties &la)
{ {
@ -204,6 +212,12 @@ TestDifferenceReceiver::begin_cell (const std::string &cellname, db::cell_index_
m_cellname = cellname; m_cellname = cellname;
} }
void
TestDifferenceReceiver::cell_meta_info_differs (const std::string &name, const tl::Variant &va, const tl::Variant &vb)
{
m_os << "layout_diff: cell meta info differs for cell " << m_cellname << " - " << name << ": " << va.to_string () << " vs. " << vb.to_string () << std::endl;
}
void void
TestDifferenceReceiver::begin_inst_differences () TestDifferenceReceiver::begin_inst_differences ()
{ {
@ -1704,4 +1718,46 @@ TEST(8)
); );
} }
// meta info
TEST(9)
{
db::Layout a;
db::cell_index_type caa = a.add_cell ("A");
db::cell_index_type cab = a.add_cell ("B");
db::Layout b;
db::cell_index_type cba = b.add_cell ("A");
db::cell_index_type cbb = b.add_cell ("B");
a.add_meta_info ("x", db::MetaInfo ("", 17.0, true));
a.add_meta_info ("y", db::MetaInfo ("", -1.0, false)); // not persisted
a.add_meta_info ("z", db::MetaInfo ("", -1.0, true));
a.add_meta_info (caa, "a1", db::MetaInfo ("", "a", true));
a.add_meta_info (caa, "a2", db::MetaInfo ("", 42, false)); // not persisted
a.add_meta_info (caa, "a3", db::MetaInfo ("", 41, true));
a.add_meta_info (cab, "b1", db::MetaInfo ("", "b", true));
a.add_meta_info (cab, "b2", db::MetaInfo ("", 3, false)); // not persisted
a.add_meta_info (cab, "b3", db::MetaInfo ("", "q", true));
b.add_meta_info ("x", db::MetaInfo ("", 21.0, true));
b.add_meta_info ("y", db::MetaInfo ("", -1.0, true));
b.add_meta_info (cba, "a1", db::MetaInfo ("", "aa", true));
b.add_meta_info (cba, "a2", db::MetaInfo ("", 42, true));
b.add_meta_info (cbb, "b1", db::MetaInfo ("", "bb", true));
b.add_meta_info (cbb, "b2", db::MetaInfo ("", 3, true));
TestDifferenceReceiver r;
bool eq = db::compare_layouts (a, b, db::layout_diff::f_verbose | db::layout_diff::f_with_meta, 0, r);
EXPECT_EQ (eq, false);
EXPECT_EQ (r.text (),
"layout_diff: global meta info differs x: 17 vs. 21\n"
"layout_diff: global meta info differs y: nil vs. -1\n"
"layout_diff: global meta info differs z: -1 vs. nil\n"
"layout_diff: cell meta info differs for cell A - a1: a vs. aa\n"
"layout_diff: cell meta info differs for cell A - a2: nil vs. 42\n"
"layout_diff: cell meta info differs for cell A - a3: 41 vs. nil\n"
"layout_diff: cell meta info differs for cell B - b1: b vs. bb\n"
"layout_diff: cell meta info differs for cell B - b2: nil vs. 3\n"
"layout_diff: cell meta info differs for cell B - b3: q vs. nil\n"
);
}

View File

@ -702,7 +702,8 @@ module DRC
@l2n = RBA::LayoutToNetlist::new(@engine._dss) @l2n = RBA::LayoutToNetlist::new(@engine._dss)
else else
layout = @engine.source.layout layout = @engine.source.layout
@l2n = RBA::LayoutToNetlist::new(layout.top_cell.name, layout.dbu) cell_name = @engine.source.cell_name
@l2n = RBA::LayoutToNetlist::new(cell_name, layout.dbu)
end end
@l2n.name = "DRC" @l2n.name = "DRC"

View File

@ -1636,3 +1636,39 @@ TEST(91d_zero_distance_mode)
{ {
run_test (_this, "91", true); run_test (_this, "91", true);
} }
TEST(92_issue1594_dual_top)
{
std::string rs = tl::testdata ();
rs += "/drc/issue_1594.drc";
std::string input = tl::testdata ();
input += "/drc/issue_1594.gds";
std::string au = tl::testdata ();
au += "/drc/issue_1594_au.cir";
std::string output = this->tmp_file ("tmp.cir");
{
// Set some variables
lym::Macro config;
config.set_text (tl::sprintf (
"$drc_force_gc = true\n"
"$drc_test_source = '%s'\n"
"$drc_test_target = '%s'\n"
, input, output)
);
config.set_interpreter (lym::Macro::Ruby);
EXPECT_EQ (config.run (), 0);
}
lym::Macro drc;
drc.load_from (rs);
EXPECT_EQ (drc.run (), 0);
// verify
CHECKPOINT ();
compare_netlists (_this, output, au);
}

View File

@ -41,6 +41,8 @@
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QGroupBox> #include <QGroupBox>
#include <QScrollBar> #include <QScrollBar>
#include <QScrollArea>
#include <QToolButton>
namespace edt namespace edt
{ {
@ -294,32 +296,32 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P
mp_parameters_area = new QScrollArea (this); mp_parameters_area = new QScrollArea (this);
mp_parameters_area->setFrameShape (QFrame::NoFrame); mp_parameters_area->setFrameShape (QFrame::NoFrame);
mp_parameters_area->setWidgetResizable (true);
QGridLayout *frame_layout = dynamic_cast<QGridLayout *> (QFrame::layout ()); QGridLayout *frame_layout = dynamic_cast<QGridLayout *> (QFrame::layout ());
frame_layout->addWidget (mp_parameters_area, 2, 0, 1, 1); frame_layout->addWidget (mp_parameters_area, 2, 0, 1, 1);
frame_layout->setRowStretch (2, 1); frame_layout->setRowStretch (2, 1);
QFrame *fi = new QFrame (mp_parameters_area); mp_main_frame = new QFrame (mp_parameters_area);
QWidget *inner_frame = fi; mp_main_frame->setFrameShape (QFrame::NoFrame);
fi->setFrameShape (QFrame::NoFrame);
setFrameShape (QFrame::NoFrame); setFrameShape (QFrame::NoFrame);
QGridLayout *inner_grid = new QGridLayout (inner_frame); QGridLayout *main_grid = new QGridLayout (mp_main_frame);
inner_frame->setLayout (inner_grid); mp_main_frame->setLayout (main_grid);
if (m_dense) { if (m_dense) {
inner_grid->setContentsMargins (4, 4, 4, 4); main_grid->setContentsMargins (4, 4, 4, 4);
inner_grid->setHorizontalSpacing (6); main_grid->setHorizontalSpacing (6);
inner_grid->setVerticalSpacing (2); main_grid->setVerticalSpacing (2);
} }
QWidget *main_frame = inner_frame;
QGridLayout *main_grid = inner_grid;
if (! mp_pcell_decl) { if (! mp_pcell_decl) {
mp_parameters_area->setWidget (main_frame); mp_parameters_area->setWidget (mp_main_frame);
update_current_parameters (); update_current_parameters ();
return; return;
} }
QWidget *inner_frame = mp_main_frame;
QGridLayout *inner_grid = main_grid;
int main_row = 0; int main_row = 0;
int row = 0; int row = 0;
std::string group_title; std::string group_title;
@ -362,7 +364,8 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P
if (! gt.empty ()) { if (! gt.empty ()) {
// create a new group // create a new group
QGroupBox *gb = new QGroupBox (main_frame); QGroupBox *gb = new QGroupBox (mp_main_frame);
mp_groups.push_back (gb);
gb->setTitle (tl::to_qstring (gt)); gb->setTitle (tl::to_qstring (gt));
main_grid->addWidget (gb, main_row, 0, 1, 3); main_grid->addWidget (gb, main_row, 0, 1, 3);
@ -382,7 +385,7 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P
// back to the main group // back to the main group
inner_grid = main_grid; inner_grid = main_grid;
inner_frame = main_frame; inner_frame = mp_main_frame;
row = main_row; row = main_row;
} }
@ -427,6 +430,9 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P
hb->setContentsMargins (0, 0, 0, 0); hb->setContentsMargins (0, 0, 0, 0);
f->setLayout (hb); f->setLayout (hb);
f->setFrameShape (QFrame::NoFrame); f->setFrameShape (QFrame::NoFrame);
QSizePolicy sp = f->sizePolicy ();
sp.setHorizontalStretch (1);
f->setSizePolicy (sp);
QLineEdit *le = new QLineEdit (f); QLineEdit *le = new QLineEdit (f);
hb->addWidget (le); hb->addWidget (le);
@ -434,9 +440,13 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P
le->setObjectName (tl::to_qstring (p->get_name ())); le->setObjectName (tl::to_qstring (p->get_name ()));
m_widgets.push_back (le); m_widgets.push_back (le);
QLabel *ul = new QLabel (f); if (! p->get_unit ().empty ()) {
hb->addWidget (ul, 1); QLabel *ul = new QLabel (f);
ul->setText (tl::to_qstring (p->get_unit ())); hb->addWidget (ul, 1);
ul->setText (tl::to_qstring (p->get_unit ()));
}
hb->addStretch (1);
inner_grid->addWidget (f, row, 2); inner_grid->addWidget (f, row, 2);
m_all_widgets.back ().push_back (f); m_all_widgets.back ().push_back (f);
@ -450,7 +460,10 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P
QPushButton *pb = new QPushButton (inner_frame); QPushButton *pb = new QPushButton (inner_frame);
pb->setObjectName (tl::to_qstring (p->get_name ())); pb->setObjectName (tl::to_qstring (p->get_name ()));
pb->setText (tl::to_qstring (description)); pb->setText (tl::to_qstring (description));
pb->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Preferred); QSizePolicy sp = pb->sizePolicy ();
sp.setHorizontalPolicy (QSizePolicy::Fixed);
sp.setHorizontalStretch (1);
pb->setSizePolicy (sp);
m_widgets.push_back (pb); m_widgets.push_back (pb);
inner_grid->addWidget (pb, row, 2); inner_grid->addWidget (pb, row, 2);
@ -466,6 +479,9 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P
{ {
QLineEdit *le = new QLineEdit (inner_frame); QLineEdit *le = new QLineEdit (inner_frame);
le->setObjectName (tl::to_qstring (p->get_name ())); le->setObjectName (tl::to_qstring (p->get_name ()));
QSizePolicy sp = le->sizePolicy ();
sp.setHorizontalStretch (1);
le->setSizePolicy (sp);
m_widgets.push_back (le); m_widgets.push_back (le);
inner_grid->addWidget (le, row, 2); inner_grid->addWidget (le, row, 2);
m_all_widgets.back ().push_back (le); m_all_widgets.back ().push_back (le);
@ -476,13 +492,29 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P
case db::PCellParameterDeclaration::t_layer: case db::PCellParameterDeclaration::t_layer:
{ {
lay::LayerSelectionComboBox *ly = new lay::LayerSelectionComboBox (inner_frame); QFrame *f = new QFrame (inner_frame);
QHBoxLayout *hb = new QHBoxLayout (f);
hb->setContentsMargins (0, 0, 0, 0);
f->setLayout (hb);
f->setFrameShape (QFrame::NoFrame);
QSizePolicy sp = f->sizePolicy ();
sp.setHorizontalStretch (1);
f->setSizePolicy (sp);
lay::LayerSelectionComboBox *ly = new lay::LayerSelectionComboBox (f);
hb->addWidget (ly);
ly->set_no_layer_available (true); ly->set_no_layer_available (true);
ly->set_view (mp_view, m_cv_index, true /*all layers*/); ly->set_view (mp_view, m_cv_index, true /*all layers*/);
ly->setObjectName (tl::to_qstring (p->get_name ())); ly->setObjectName (tl::to_qstring (p->get_name ()));
sp = ly->sizePolicy ();
sp.setHorizontalPolicy (QSizePolicy::Fixed);
ly->setSizePolicy (sp);
m_widgets.push_back (ly); m_widgets.push_back (ly);
inner_grid->addWidget (ly, row, 2);
m_all_widgets.back ().push_back (ly); hb->addStretch (1);
inner_grid->addWidget (f, row, 2);
m_all_widgets.back ().push_back (f);
connect (ly, SIGNAL (activated (int)), this, SLOT (parameter_changed ())); connect (ly, SIGNAL (activated (int)), this, SLOT (parameter_changed ()));
} }
@ -492,7 +524,9 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P
{ {
QCheckBox *cbx = new QCheckBox (inner_frame); QCheckBox *cbx = new QCheckBox (inner_frame);
// this makes the checkbox not stretch over the full width - better when navigating with tab // this makes the checkbox not stretch over the full width - better when navigating with tab
cbx->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Preferred)); QSizePolicy sp = cbx->sizePolicy ();
sp.setHorizontalStretch (1);
cbx->setSizePolicy (sp);
cbx->setObjectName (tl::to_qstring (p->get_name ())); cbx->setObjectName (tl::to_qstring (p->get_name ()));
m_widgets.push_back (cbx); m_widgets.push_back (cbx);
inner_grid->addWidget (cbx, row, 2); inner_grid->addWidget (cbx, row, 2);
@ -509,8 +543,20 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P
} else { } else {
QComboBox *cb = new QComboBox (inner_frame); QFrame *f = new QFrame (inner_frame);
QHBoxLayout *hb = new QHBoxLayout (f);
hb->setContentsMargins (0, 0, 0, 0);
f->setLayout (hb);
f->setFrameShape (QFrame::NoFrame);
QSizePolicy sp = f->sizePolicy ();
sp.setHorizontalStretch (1);
f->setSizePolicy (sp);
QComboBox *cb = new QComboBox (f);
hb->addWidget (cb);
cb->setObjectName (tl::to_qstring (p->get_name ())); cb->setObjectName (tl::to_qstring (p->get_name ()));
cb->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Preferred);
cb->setSizeAdjustPolicy (QComboBox::AdjustToContents);
int i = 0; int i = 0;
for (std::vector<tl::Variant>::const_iterator c = p->get_choices ().begin (); c != p->get_choices ().end (); ++c, ++i) { for (std::vector<tl::Variant>::const_iterator c = p->get_choices ().begin (); c != p->get_choices ().end (); ++c, ++i) {
@ -523,21 +569,25 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P
connect (cb, SIGNAL (activated (int)), this, SLOT (parameter_changed ())); connect (cb, SIGNAL (activated (int)), this, SLOT (parameter_changed ()));
cb->setMinimumContentsLength (30);
cb->setSizeAdjustPolicy (QComboBox::AdjustToMinimumContentsLengthWithIcon);
m_widgets.push_back (cb); m_widgets.push_back (cb);
inner_grid->addWidget (cb, row, 2);
m_all_widgets.back ().push_back (cb); hb->addStretch (1);
inner_grid->addWidget (f, row, 2);
m_all_widgets.back ().push_back (f);
} }
++row; ++row;
if (inner_frame == main_frame) { if (inner_frame == mp_main_frame) {
++main_row; ++main_row;
} }
} }
// adds some default buffer space
main_grid->setRowStretch (main_row, 1);
// initial callback // initial callback
try { try {
@ -556,8 +606,8 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P
update_widgets_from_states (m_states); update_widgets_from_states (m_states);
mp_parameters_area->setWidget (main_frame); mp_parameters_area->setWidget (mp_main_frame);
main_frame->show (); mp_main_frame->show ();
update_current_parameters (); update_current_parameters ();
} }
@ -944,15 +994,15 @@ PCellParametersPage::update_widgets_from_states (const db::ParameterStates &stat
break; break;
case db::ParameterState::InfoIcon: case db::ParameterState::InfoIcon:
m_icon_widgets [i]->setPixmap (info); m_icon_widgets [i]->setPixmap (info);
m_icon_widgets [i]->show (); m_icon_widgets [i]->setVisible (ps.is_visible ());
break; break;
case db::ParameterState::WarningIcon: case db::ParameterState::WarningIcon:
m_icon_widgets [i]->setPixmap (warning); m_icon_widgets [i]->setPixmap (warning);
m_icon_widgets [i]->show (); m_icon_widgets [i]->setVisible (ps.is_visible ());
break; break;
case db::ParameterState::ErrorIcon: case db::ParameterState::ErrorIcon:
m_icon_widgets [i]->setPixmap (error); m_icon_widgets [i]->setPixmap (error);
m_icon_widgets [i]->show (); m_icon_widgets [i]->setVisible (ps.is_visible ());
break; break;
} }
@ -961,6 +1011,12 @@ PCellParametersPage::update_widgets_from_states (const db::ParameterStates &stat
} }
set_parameters_internal (states, lazy_evaluation ()); set_parameters_internal (states, lazy_evaluation ());
// QGridLayouts are bad in handling nested QFrame (or QGroupBox) with their own layouts,
// so we help a little here:
for (auto g = mp_groups.begin (); g != mp_groups.end (); ++g) {
(*g)->resize (QSize ((*g)->width (), (*g)->sizeHint ().height ()));
}
} }
void void

View File

@ -29,10 +29,12 @@
#include "tlDeferredExecution.h" #include "tlDeferredExecution.h"
#include <QFrame> #include <QFrame>
#include <QScrollArea>
#include <QLabel> class QGroupBox;
#include <QToolButton> class QCheckBox;
#include <QCheckBox> class QLabel;
class QToolButton;
class QScrollArea;
namespace lay namespace lay
{ {
@ -150,6 +152,8 @@ private slots:
private: private:
lay::Dispatcher *mp_dispatcher; lay::Dispatcher *mp_dispatcher;
QScrollArea *mp_parameters_area; QScrollArea *mp_parameters_area;
QFrame *mp_main_frame;
std::vector<QGroupBox *> mp_groups;
QLabel *mp_error_label; QLabel *mp_error_label;
QLabel *mp_error_icon; QLabel *mp_error_icon;
QLabel *mp_changed_label; QLabel *mp_changed_label;

View File

@ -95,6 +95,16 @@ Browser::accept ()
} }
} }
void
Browser::reject ()
{
if (active ()) {
m_active = false;
deactivated ();
QDialog::reject ();
}
}
} }
#endif #endif

View File

@ -138,6 +138,7 @@ private:
void closeEvent (QCloseEvent *); void closeEvent (QCloseEvent *);
void accept (); void accept ();
void reject ();
}; };
} }

View File

@ -28,7 +28,7 @@
#include "lymMacro.h" #include "lymMacro.h"
#include "tlFileUtils.h" #include "tlFileUtils.h"
void run_test (tl::TestBase *_this, const std::string &suffix, const std::string &layout, bool with_l2n = false, const std::string &top = std::string (), bool change_case = false) void run_test (tl::TestBase *_this, const std::string &suffix, const std::string &layout, bool with_l2n = false, bool with_lvs = true, const std::string &top = std::string (), bool change_case = false)
{ {
std::string rs = tl::testdata (); std::string rs = tl::testdata ();
rs += "/lvs/" + suffix + ".lvs"; rs += "/lvs/" + suffix + ".lvs";
@ -70,7 +70,9 @@ void run_test (tl::TestBase *_this, const std::string &suffix, const std::string
lvs.load_from (rs); lvs.load_from (rs);
EXPECT_EQ (lvs.run (), 0); EXPECT_EQ (lvs.run (), 0);
_this->compare_text_files (output_lvsdb, au_lvsdb); if (with_lvs) {
_this->compare_text_files (output_lvsdb, au_lvsdb);
}
_this->compare_text_files (output_cir, au_cir); _this->compare_text_files (output_cir, au_cir);
if (with_l2n) { if (with_l2n) {
_this->compare_text_files (output_l2n, au_l2n); _this->compare_text_files (output_l2n, au_l2n);
@ -121,14 +123,14 @@ TEST(6_simple_pin_swapping)
{ {
run_test (_this, "ringo_simple_pin_swapping", "ringo.gds"); run_test (_this, "ringo_simple_pin_swapping", "ringo.gds");
// change case // change case
run_test (_this, "ringo_simple_pin_swapping", "ringo.gds", false, std::string (), true); run_test (_this, "ringo_simple_pin_swapping", "ringo.gds", false, true, std::string (), true);
} }
TEST(7_net_and_circuit_equivalence) TEST(7_net_and_circuit_equivalence)
{ {
run_test (_this, "ringo_simple_net_and_circuit_equivalence", "ringo_renamed.gds"); run_test (_this, "ringo_simple_net_and_circuit_equivalence", "ringo_renamed.gds");
// change case // change case
run_test (_this, "ringo_simple_net_and_circuit_equivalence", "ringo_renamed.gds", false, std::string (), true); run_test (_this, "ringo_simple_net_and_circuit_equivalence", "ringo_renamed.gds", false, true, std::string (), true);
} }
TEST(8_simplification) TEST(8_simplification)
@ -166,7 +168,7 @@ TEST(13_simple_ringo_device_subcircuits)
{ {
run_test (_this, "ringo_device_subcircuits", "ringo.gds"); run_test (_this, "ringo_device_subcircuits", "ringo.gds");
// change case // change case
run_test (_this, "ringo_device_subcircuits", "ringo.gds", false, std::string (), true); run_test (_this, "ringo_device_subcircuits", "ringo.gds", false, true, std::string (), true);
} }
TEST(14_simple_ringo_mixed_hierarchy) TEST(14_simple_ringo_mixed_hierarchy)
@ -181,7 +183,7 @@ TEST(15_simple_dummy_device)
TEST(16_floating) TEST(16_floating)
{ {
run_test (_this, "floating", "floating.gds", false, "TOP"); run_test (_this, "floating", "floating.gds", false, true, "TOP");
} }
TEST(17_layout_variants) TEST(17_layout_variants)
@ -287,3 +289,9 @@ TEST(31_MustConnect2)
run_test (_this, "must_connect2", "must_connect2.gds"); run_test (_this, "must_connect2", "must_connect2.gds");
} }
// issue 1609
TEST(40_DeviceExtractorErrors)
{
run_test (_this, "custom_resistors", "custom_resistors.gds", true, false /*no LVS*/);
}

View File

@ -165,7 +165,7 @@ TEST(20_private)
TEST(21_private) TEST(21_private)
{ {
run_test (_this, "test_21.lylvs", "test_21.cir.gz", "test_21.gds.gz", true, "test_21_3.lvsdb"); run_test (_this, "test_21.lylvs", "test_21.cir.gz", "test_21.gds.gz", true, "test_21_4.lvsdb");
} }
// issue #1021 // issue #1021

View File

@ -816,7 +816,9 @@ De Boor algorithm for NURBS
static db::DPoint static db::DPoint
b_spline_point (double x, const std::vector<std::pair<db::DPoint, double> > &control_points, int p, const std::vector<double> &t, int &k) b_spline_point (double x, const std::vector<std::pair<db::DPoint, double> > &control_points, int p, const std::vector<double> &t, int &k)
{ {
k = (int) (std::lower_bound (t.begin (), t.end (), x - 1e-6) - t.begin ()); double eps = 1e-12 * (fabs (t.back ()) + fabs (t.front ()));
k = (int) (std::lower_bound (t.begin (), t.end (), x - eps) - t.begin ());
--k; --k;
if (k < p) { if (k < p) {
k = p; k = p;
@ -882,6 +884,12 @@ spline_interpolate (std::list<db::DPoint> &curve_points,
db::DPoint s1 = b_spline_point (t_start + 0.5 * dt, control_points, degree, knots, k1); db::DPoint s1 = b_spline_point (t_start + 0.5 * dt, control_points, degree, knots, k1);
db::DPoint s2 = b_spline_point (t_start + 1.5 * dt, control_points, degree, knots, k2); db::DPoint s2 = b_spline_point (t_start + 1.5 * dt, control_points, degree, knots, k2);
if (s1.to_string () == "-2.60657790172,-1.78843428245") {
tl::info << "@@@ BANG!";
}
if (s2.to_string () == "-2.60657790172,-1.78843428245") {
tl::info << "@@@ BANG!";
}
db::DVector p1 (s1, *current_curve_point); db::DVector p1 (s1, *current_curve_point);
db::DVector p2 (*pm, s1); db::DVector p2 (*pm, s1);
@ -1740,6 +1748,7 @@ DXFReader::read_entities (db::Layout &layout, db::Cell &cell, const db::DVector
std::string layer; std::string layer;
unsigned int xy_flag = 0; unsigned int xy_flag = 0;
int degree = 1; int degree = 1;
int flags = 0;
while ((g = read_group_code ()) != 0) { while ((g = read_group_code ()) != 0) {
if (g == 8) { if (g == 8) {
@ -1763,9 +1772,9 @@ DXFReader::read_entities (db::Layout &layout, db::Cell &cell, const db::DVector
} else if (g == 70) { } else if (g == 70) {
int flags = read_int32 (); flags = read_int32 ();
if (flags != 8 && flags != 12) { if ((flags & 2) != 0) {
warn ("Invalid SPLINE flag (code 70): " + tl::to_string (flags) + ". Only types 8 (non-rational) and 12 (rational) are supported currently."); warn ("Invalid SPLINE flag (code 70): " + tl::to_string (flags) + ". Periodic splines not supported currently.");
} }
} else if (g == 71) { } else if (g == 71) {
@ -1814,6 +1823,13 @@ DXFReader::read_entities (db::Layout &layout, db::Cell &cell, const db::DVector
} }
} }
} else if ((flags & 1) && m_polyline_mode == 2) {
// create a polygon for the spline
db::DSimplePolygon p;
p.assign_hull (new_points.begin (), new_points.end (), tt);
cell.shapes (ll.second).insert (safe_from_double (p));
} else { } else {
// create a path with width 0 for the spline // create a path with width 0 for the spline

View File

@ -536,3 +536,20 @@ TEST(35c)
db::DXFReaderOptions opt; db::DXFReaderOptions opt;
run_test_public (_this, "issue_1422c.dxf", "issue_1422c_au.gds.gz", opt); run_test_public (_this, "issue_1422c.dxf", "issue_1422c_au.gds.gz", opt);
} }
// issue #1592, polyline mode 2
TEST(36a)
{
db::DXFReaderOptions opt;
opt.dbu = 1e-5;
opt.polyline_mode = 2;
run_test_public (_this, "issue_1592.dxf.gz", "issue_1592a_au.oas.gz", opt, true);
}
// issue #1592
TEST(36b)
{
db::DXFReaderOptions opt;
opt.dbu = 1e-5;
run_test_public (_this, "issue_1592.dxf.gz", "issue_1592b_au.oas.gz", opt, true);
}

View File

@ -538,7 +538,7 @@ TEST(4_CollectModeRename)
} }
std::string fn_au (tl::testdata () + "/gds/collect_rename_au.gds"); std::string fn_au (tl::testdata () + "/gds/collect_rename_au.gds");
db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1); db::compare_layouts (_this, layout, fn_au, db::NormalizationMode (db::WriteGDS2 | db::WithMeta), 1);
} }
TEST(4_CollectModeRenameWithGhost) TEST(4_CollectModeRenameWithGhost)
@ -634,7 +634,7 @@ TEST(4_CollectModeOverwrite)
} }
std::string fn_au (tl::testdata () + "/gds/collect_overwrite_au.gds"); std::string fn_au (tl::testdata () + "/gds/collect_overwrite_au.gds");
db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1); db::compare_layouts (_this, layout, fn_au, db::NormalizationMode (db::WriteGDS2 | db::WithMeta), 1);
} }
TEST(4_CollectModeSkip) TEST(4_CollectModeSkip)
@ -658,7 +658,7 @@ TEST(4_CollectModeSkip)
} }
std::string fn_au (tl::testdata () + "/gds/collect_skip_au.gds"); std::string fn_au (tl::testdata () + "/gds/collect_skip_au.gds");
db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1); db::compare_layouts (_this, layout, fn_au, db::NormalizationMode (db::WriteGDS2 | db::WithMeta), 1);
} }
TEST(4_CollectModeAdd) TEST(4_CollectModeAdd)
@ -682,7 +682,7 @@ TEST(4_CollectModeAdd)
} }
std::string fn_au (tl::testdata () + "/gds/collect_add_au.gds"); std::string fn_au (tl::testdata () + "/gds/collect_add_au.gds");
db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1); db::compare_layouts (_this, layout, fn_au, db::NormalizationMode (db::WriteGDS2 | db::WithMeta), 1);
} }
// border case with multiple padding 0 for SNAME and STRING records // border case with multiple padding 0 for SNAME and STRING records

View File

@ -6,8 +6,8 @@ TARGET = gds2_tests
include($$PWD/../../../../lib_ut.pri) include($$PWD/../../../../lib_ut.pri)
SOURCES = \ SOURCES = \
dbGDS2Reader.cc \ dbGDS2ReaderTests.cc \
dbGDS2Writer.cc \ dbGDS2WriterTests.cc
INCLUDEPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin $$PWD/../../../common INCLUDEPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin $$PWD/../../../common
DEPENDPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin $$PWD/../../../common DEPENDPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin $$PWD/../../../common

View File

@ -1098,7 +1098,7 @@ LEFDEFReaderState::read_single_map_file (const std::string &path, std::map<std::
// List of purposes corresponding to ALL // List of purposes corresponding to ALL
LayerPurpose all_purposes[] = { LayerPurpose all_purposes[] = {
LEFPins, Pins, Fills, FillsOPC, Obstructions, SpecialRouting, Routing, ViaGeometry LEFPins, Pins, SpecialRouting, Routing, ViaGeometry
}; };
while (! ts.at_end ()) { while (! ts.at_end ()) {

View File

@ -420,7 +420,7 @@ TEST(def15)
{ {
db::LEFDEFReaderOptions opt = default_options (); db::LEFDEFReaderOptions opt = default_options ();
opt.set_macro_resolution_mode (1); opt.set_macro_resolution_mode (1);
run_test (_this, "def15", "map:test.map+lef:tech.lef+def:test.def", "au2.oas.gz", opt); run_test (_this, "def15", "map:test.map+lef:tech.lef+def:test.def", "au2_2.oas.gz", opt);
} }
TEST(def16) TEST(def16)
@ -814,7 +814,7 @@ TEST(117_mapfile_all)
"'+M1.LEFOBS;M1.LEFPIN;M1.NET;M1.PIN;M1.SPNET;M1.VIA : \\'M1.NET/PIN/SPNET/...\\' (1/5)';" "'+M1.LEFOBS;M1.LEFPIN;M1.NET;M1.PIN;M1.SPNET;M1.VIA : \\'M1.NET/PIN/SPNET/...\\' (1/5)';"
"'+M1.NET;M1.SPNET : \\'M1.NET/SPNET\\' (16/0)';" "'+M1.NET;M1.SPNET : \\'M1.NET/SPNET\\' (16/0)';"
"'+M1.NET : M1.NET (18/0)';" "'+M1.NET : M1.NET (18/0)';"
"'+M1.FILL;M1.FILLOPC;M1.LEFOBS;M1.LEFPIN;M1.NET;M1.PIN;M1.SPNET;M1.VIA : \\'M1.NET/PIN/FILL/...\\' (22/2)';" "'+M1.LEFPIN;M1.NET;M1.PIN;M1.SPNET;M1.VIA : \\'M1.NET/PIN/SPNET/...\\' (22/2)';"
"'+\\'M1.NET:1\\';\\'M1.PIN:1\\';\\'M1.SPNET:1\\';\\'M1.VIA:1\\' : \\'M1.NET:1/PIN:1/...\\' (6/0)';" "'+\\'M1.NET:1\\';\\'M1.PIN:1\\';\\'M1.SPNET:1\\';\\'M1.VIA:1\\' : \\'M1.NET:1/PIN:1/...\\' (6/0)';"
"'+\\'M1.NET:1\\' : \\'M1.NET:1\\' (7/0)';" "'+\\'M1.NET:1\\' : \\'M1.NET:1\\' (7/0)';"
"'+M1.PIN : M1.PIN (3/0)';" "'+M1.PIN : M1.PIN (3/0)';"
@ -822,7 +822,7 @@ TEST(117_mapfile_all)
"'+M1.FILL : M1.FILL (14/0)';" "'+M1.FILL : M1.FILL (14/0)';"
"'+M1.FILL : M1.FILL (15/0)';" "'+M1.FILL : M1.FILL (15/0)';"
"'+M1.FILL : M1.FILL (17/0)';" "'+M1.FILL : M1.FILL (17/0)';"
"'+M1.FILLOPC : M1.FILLOPC (9/0)';" "'M1.FILLOPC : M1.FILLOPC (9/0)';"
"'\\'M1.FILLOPC:1\\' : \\'M1.FILLOPC:1\\' (10/0)';" "'\\'M1.FILLOPC:1\\' : \\'M1.FILLOPC:1\\' (10/0)';"
"'\\'M1.FILLOPC:2\\' : \\'M1.FILLOPC:2\\' (11/0)';" "'\\'M1.FILLOPC:2\\' : \\'M1.FILLOPC:2\\' (11/0)';"
"'\\'M1.VIA:SIZE0.05X0.05\\' : \\'M1.VIA:SIZE0.05X0.05\\' (20/0)';" "'\\'M1.VIA:SIZE0.05X0.05\\' : \\'M1.VIA:SIZE0.05X0.05\\' (20/0)';"

View File

@ -103,6 +103,7 @@ public:
PythonStackTraceProvider (PyFrameObject *frame, const std::string &scope) PythonStackTraceProvider (PyFrameObject *frame, const std::string &scope)
: m_scope (scope) : m_scope (scope)
{ {
PythonRef frame_object_ref;
while (frame != NULL) { while (frame != NULL) {
#if PY_VERSION_HEX >= 0x030A0000 #if PY_VERSION_HEX >= 0x030A0000
@ -123,6 +124,8 @@ public:
#if PY_VERSION_HEX >= 0x030A0000 #if PY_VERSION_HEX >= 0x030A0000
frame = PyFrame_GetBack(frame); frame = PyFrame_GetBack(frame);
// PyFrame_GetBack returns a strong reference, hence we need to make sure it is released
frame_object_ref = (PyObject *) frame;
#else #else
frame = frame->f_back; frame = frame->f_back;
#endif #endif

15
testdata/drc/issue_1594.drc vendored Normal file
View File

@ -0,0 +1,15 @@
source($drc_test_source, "TOP1")
# This is just a smoke test without actual devices
l1 = input(1, 0)
l2 = input(2, 0)
l3 = input(3, 0)
connect(l1, l2)
connect(l2, l3)
writer = RBA::NetlistSpiceWriter::new
netlist.write($drc_test_target, writer, "netlist")

BIN
testdata/drc/issue_1594.gds vendored Normal file

Binary file not shown.

5
testdata/drc/issue_1594_au.cir vendored Normal file
View File

@ -0,0 +1,5 @@
* netlist
* cell TOP1
.SUBCKT TOP1
.ENDS TOP1

BIN
testdata/dxf/issue_1592.dxf.gz vendored Normal file

Binary file not shown.

BIN
testdata/dxf/issue_1592a_au.oas.gz vendored Normal file

Binary file not shown.

BIN
testdata/dxf/issue_1592b_au.oas.gz vendored Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

18
testdata/lvs/custom_resistors.cir vendored Normal file
View File

@ -0,0 +1,18 @@
* cell TOP
.SUBCKT TOP
* cell instance $1 r180 *1 2,2.6
X$1 6 1 A
* cell instance $2 r0 *1 2.2,1
X$2 6 5 A
* device instance $1 r0 *1 0.8,0.75 RPP1
R$1 2 1 0.555555555556 RPP1
.ENDS TOP
* cell A
* pin
* pin
.SUBCKT A 1 2
* device instance $1 r0 *1 -0.2,0.4 RPP1
R$1 1 2 1.25 RPP1
.ENDS A

BIN
testdata/lvs/custom_resistors.gds vendored Normal file

Binary file not shown.

103
testdata/lvs/custom_resistors.l2n.1 vendored Normal file
View File

@ -0,0 +1,103 @@
#%l2n-klayout
W(TOP)
U(0.001)
L(l4 '15/0')
L(l3 '16/0')
L(l1)
C(l4 l4 l3 l1)
C(l3 l4 l3)
C(l1 l4 l1)
H(E B('Resistor shape does not touch marker border in exactly two places') C(TOP) X('device-extract') Q('(0.8,0.75;0.8,1.15;1,1.15;1,0.75)'))
H(E B('Resistor shape does not touch marker border in exactly two places') C(TOP) X('device-extract') Q('(0,0.75;0,1.15;0.2,1.15;0.2,0.75)'))
H(E B('Resistor shape does not touch marker border in exactly two places') C(A) X('device-extract') Q('(0.85,-0.4;0.85,-0.2;1.25,-0.2;1.25,-0.4)'))
K(RPP1 RES)
D(D$RPP1 RPP1
T(A
R(l1 (0 400) (200 300))
)
T(B
R(l1 (0 1200) (200 250))
)
)
D(D$RPP1$1 RPP1
T(A
R(l1 (0 0) (250 200))
)
T(B
R(l1 (750 0) (250 200))
)
)
X(A
R((-200 -450) (1750 1350))
N(1
R(l4 (-150 450) (100 100))
R(l3 (-150 -150) (200 500))
R(l1 (-200 -500) (250 200))
)
N(2
R(l4 (650 450) (100 100))
R(l4 (-100 -900) (100 100))
R(l3 (-150 200) (200 650))
R(l3 (-200 -1000) (200 500))
R(l1 (-250 300) (250 200))
R(l1 (-200 -1000) (250 200))
)
N(3
R(l4 (1450 -350) (100 100))
)
P(1)
P(2)
D(1 D$RPP1$1
Y(-200 400)
E(R 1.25)
E(L 0.5)
E(W 0.2)
E(A 0.1)
E(P 1.4)
T(A 1)
T(B 2)
)
)
X(TOP
R((-50 450) (3800 2600))
N(1
R(l4 (850 2050) (100 100))
R(l3 (-150 -150) (500 200))
R(l1 (-500 -250) (200 250))
)
N(2
R(l4 (850 1250) (100 100))
R(l4 (-100 -100) (100 100))
R(l4 (-900 -100) (100 100))
R(l3 (200 -150) (650 200))
R(l3 (-1000 -200) (500 200))
R(l1 (300 -250) (200 300))
R(l1 (-1000 -300) (200 250))
)
N(3
R(l4 (50 450) (100 100))
)
N(4
R(l4 (850 450) (100 100))
)
N(5)
N(6)
D(1 D$RPP1
Y(800 750)
E(R 0.555555555556)
E(L 0.333333333333)
E(W 0.3)
E(A 0.1)
E(P 1.26666666667)
T(A 2)
T(B 1)
)
X(1 A O(180) Y(2000 2600)
P(0 6)
P(1 1)
)
X(2 A Y(2200 1000)
P(0 6)
P(1 5)
)
)

103
testdata/lvs/custom_resistors.l2n.2 vendored Normal file
View File

@ -0,0 +1,103 @@
#%l2n-klayout
W(TOP)
U(0.001)
L(l4 '15/0')
L(l3 '16/0')
L(l1)
C(l4 l4 l3 l1)
C(l3 l4 l3)
C(l1 l4 l1)
H(E B('Resistor shape does not touch marker border in exactly two places') C(TOP) X('device-extract') Q('(0,0.75;0,1.15;0.2,1.15;0.2,0.75)'))
H(E B('Resistor shape does not touch marker border in exactly two places') C(TOP) X('device-extract') Q('(0.8,0.75;0.8,1.15;1,1.15;1,0.75)'))
H(E B('Resistor shape does not touch marker border in exactly two places') C(A) X('device-extract') Q('(0.85,-0.4;0.85,-0.2;1.25,-0.2;1.25,-0.4)'))
K(RPP1 RES)
D(D$RPP1 RPP1
T(A
R(l1 (0 400) (200 300))
)
T(B
R(l1 (0 1200) (200 250))
)
)
D(D$RPP1$1 RPP1
T(A
R(l1 (0 0) (250 200))
)
T(B
R(l1 (750 0) (250 200))
)
)
X(A
R((-200 -450) (1750 1350))
N(1
R(l4 (-150 450) (100 100))
R(l3 (-150 -150) (200 500))
R(l1 (-200 -500) (250 200))
)
N(2
R(l4 (650 450) (100 100))
R(l4 (-100 -900) (100 100))
R(l3 (-150 200) (200 650))
R(l3 (-200 -1000) (200 500))
R(l1 (-250 300) (250 200))
R(l1 (-200 -1000) (250 200))
)
N(3
R(l4 (1450 -350) (100 100))
)
P(1)
P(2)
D(1 D$RPP1$1
Y(-200 400)
E(R 1.25)
E(L 0.5)
E(W 0.2)
E(A 0.1)
E(P 1.4)
T(A 1)
T(B 2)
)
)
X(TOP
R((-50 450) (3800 2600))
N(1
R(l4 (850 2050) (100 100))
R(l3 (-150 -150) (500 200))
R(l1 (-500 -250) (200 250))
)
N(2
R(l4 (850 1250) (100 100))
R(l4 (-100 -100) (100 100))
R(l4 (-900 -100) (100 100))
R(l3 (200 -150) (650 200))
R(l3 (-1000 -200) (500 200))
R(l1 (300 -250) (200 300))
R(l1 (-1000 -300) (200 250))
)
N(3
R(l4 (50 450) (100 100))
)
N(4
R(l4 (850 450) (100 100))
)
N(5)
N(6)
D(1 D$RPP1
Y(800 750)
E(R 0.555555555556)
E(L 0.333333333333)
E(W 0.3)
E(A 0.1)
E(P 1.26666666667)
T(A 2)
T(B 1)
)
X(1 A O(180) Y(2000 2600)
P(0 6)
P(1 1)
)
X(2 A Y(2200 1000)
P(0 6)
P(1 5)
)
)

86
testdata/lvs/custom_resistors.lvs vendored Normal file
View File

@ -0,0 +1,86 @@
source($lvs_test_source, "TOP")
report_netlist($lvs_test_target_l2n)
target_netlist($lvs_test_target_cir)
deep
# -------------------------------------------------------------------
# Layers
poly_dg = input(13, 0)
cont = input(15, 0)
met1_dg = input(16, 0)
sblk = input(34, 0)
rp_1 = sblk & poly_dg
p1trm = poly_dg - rp_1
class ResistorExtractor < RBA::GenericDeviceExtractor
def initialize(name, sheet_rho)
self.name = name
@sheet_rho = sheet_rho
end
def setup
define_layer("C", "Conductor")
define_layer("R", "Resistor")
register_device_class(RBA::DeviceClassResistor::new)
end
def get_connectivity(layout, layers)
# this "connectivity" forms the shape clusters that make up the device
conn = RBA::Connectivity::new
conn.connect(layers[0], layers[1]) # collect touching contacts
conn.connect(layers[1], layers[1]) # combine resistor shapes into one area
conn
end
def extract_devices(layer_geometry)
# layer_geometry provides the input layers in the order they are defined with "define_layer"
conductor = layer_geometry[0]
resistor = layer_geometry[1]
resistor_regions = resistor.merged
resistor_regions.each do |r|
terminals = conductor.interacting(RBA::Region::new(r))
if terminals.size != 2
error("Resistor shape does not touch marker border in exactly two places", r)
else
double_width = 0
(terminals.edges & resistor.edges).merged.each do |e|
double_width += e.length
end
# A = L*W
# -> L = A/W
a = r.area*dbu*dbu
w = (double_width / 2.0)*dbu
l = a / w
device = create_device
device.set_parameter(RBA::DeviceClassResistor::PARAM_R, @sheet_rho * l / w);
device.set_parameter(RBA::DeviceClassResistor::PARAM_A, a)
device.set_parameter(RBA::DeviceClassResistor::PARAM_L, l)
device.set_parameter(RBA::DeviceClassResistor::PARAM_P, 2*l+2*w)
device.set_parameter(RBA::DeviceClassResistor::PARAM_W, w)
define_terminal(device, "A", "C", terminals[0]);
define_terminal(device, "B", "C", terminals[1]);
end
end
end
end
extract_devices(ResistorExtractor::new("RPP1", 0.5), # intentionally wrong: 1565.15/5
{ "C" => p1trm, "R" => rp_1 })
connect(met1_dg, cont)
connect(p1trm, cont)
begin
netlist
rescue => ex
end

View File

@ -23,6 +23,10 @@ end
load("test_prologue.rb") load("test_prologue.rb")
def mi2s(obj)
obj.each_meta_info.collect { |mi| mi.name + ":" + mi.value.to_s }.sort.join(";")
end
class DBLayoutTests2_TestClass < TestBase class DBLayoutTests2_TestClass < TestBase
# LayerInfo # LayerInfo
@ -1253,6 +1257,175 @@ class DBLayoutTests2_TestClass < TestBase
end end
# Cell#read and meta info (issue #1609)
def test_16
tmp = File::join($ut_testtmp, "test16.gds")
ly1 = RBA::Layout::new
a = ly1.create_cell("A")
b = ly1.create_cell("B")
a.insert(RBA::DCellInstArray::new(b, RBA::Trans::new))
a.add_meta_info(RBA::LayoutMetaInfo::new("am1", 42.0, "", true))
a.add_meta_info(RBA::LayoutMetaInfo::new("am2", "u", "", true))
assert_equal(mi2s(a), "am1:42.0;am2:u")
b.add_meta_info(RBA::LayoutMetaInfo::new("bm1", 17, "", true))
assert_equal(mi2s(b), "bm1:17")
ly1.add_meta_info(RBA::LayoutMetaInfo::new("lm1", -2.0, "", true))
ly1.add_meta_info(RBA::LayoutMetaInfo::new("lm2", "v", "", true))
assert_equal(mi2s(ly1), "lm1:-2.0;lm2:v")
ly1.write(tmp)
ly2 = RBA::Layout::new
top = ly2.create_cell("TOP")
a = ly2.create_cell("A")
c = ly2.create_cell("C")
top.insert(RBA::DCellInstArray::new(a, RBA::Trans::new))
a.insert(RBA::DCellInstArray::new(c, RBA::Trans::new))
top.add_meta_info(RBA::LayoutMetaInfo::new("topm1", "abc"))
assert_equal(mi2s(top), "topm1:abc")
a.add_meta_info(RBA::LayoutMetaInfo::new("am1", "a number"))
a.add_meta_info(RBA::LayoutMetaInfo::new("am3", 0))
assert_equal(mi2s(a), "am1:a number;am3:0")
c.add_meta_info(RBA::LayoutMetaInfo::new("cm1", 3))
assert_equal(mi2s(c), "cm1:3")
ly2.add_meta_info(RBA::LayoutMetaInfo::new("lm1", 5))
assert_equal(mi2s(ly2), "lm1:5")
a.read(tmp)
# not modified
assert_equal(mi2s(ly2), "lm1:5")
# merged
assert_equal(mi2s(a), "am1:42.0;am2:u;am3:0")
# not modified
assert_equal(mi2s(c), "cm1:3")
b2 = ly2.cell("B")
# imported
assert_equal(mi2s(b2), "bm1:17")
puts "done."
end
# Layout, meta info diverse
def test_17
manager = RBA::Manager::new
ly = RBA::Layout::new(manager)
a = ly.create_cell("A")
manager.transaction("trans")
ly.add_meta_info(RBA::LayoutMetaInfo::new("lm1", 17))
a.add_meta_info(RBA::LayoutMetaInfo::new("am1", "u"))
manager.commit
assert_equal(mi2s(ly), "lm1:17")
assert_equal(mi2s(a), "am1:u")
manager.undo
assert_equal(mi2s(ly), "")
assert_equal(mi2s(a), "")
manager.redo
assert_equal(mi2s(ly), "lm1:17")
assert_equal(mi2s(a), "am1:u")
manager.transaction("trans")
ly.add_meta_info(RBA::LayoutMetaInfo::new("lm1", 117))
a.add_meta_info(RBA::LayoutMetaInfo::new("am1", "v"))
manager.commit
assert_equal(mi2s(ly), "lm1:117")
assert_equal(mi2s(a), "am1:v")
manager.undo
assert_equal(mi2s(ly), "lm1:17")
assert_equal(mi2s(a), "am1:u")
manager.redo
assert_equal(mi2s(ly), "lm1:117")
assert_equal(mi2s(a), "am1:v")
manager.undo
assert_equal(mi2s(ly), "lm1:17")
assert_equal(mi2s(a), "am1:u")
manager.transaction("trans")
ly.remove_meta_info("lm1")
a.remove_meta_info("am1")
a.remove_meta_info("doesnotexist")
manager.commit
assert_equal(mi2s(ly), "")
assert_equal(mi2s(a), "")
manager.undo
assert_equal(mi2s(ly), "lm1:17")
assert_equal(mi2s(a), "am1:u")
manager.transaction("trans")
ly.clear_all_meta_info
manager.commit
assert_equal(mi2s(ly), "")
assert_equal(mi2s(a), "")
manager.undo
assert_equal(mi2s(ly), "lm1:17")
assert_equal(mi2s(a), "am1:u")
manager.redo
assert_equal(mi2s(ly), "")
assert_equal(mi2s(a), "")
ly2 = RBA::Layout::new
ly.add_meta_info(RBA::LayoutMetaInfo::new("lm1", 17))
ly2.add_meta_info(RBA::LayoutMetaInfo::new("lm2", 42))
assert_equal(mi2s(ly), "lm1:17")
ly.merge_meta_info(ly2)
assert_equal(mi2s(ly), "lm1:17;lm2:42")
ly.copy_meta_info(ly2)
assert_equal(mi2s(ly), "lm2:42")
a = ly.create_cell("A")
a.add_meta_info(RBA::LayoutMetaInfo::new("am1", "u"))
b = ly2.create_cell("B")
b.add_meta_info(RBA::LayoutMetaInfo::new("bm1", "v"))
assert_equal(mi2s(a), "am1:u")
a.merge_meta_info(b)
assert_equal(mi2s(a), "am1:u;bm1:v")
a.copy_meta_info(b)
assert_equal(mi2s(a), "bm1:v")
ly = RBA::Layout::new
ly2 = RBA::Layout::new
a = ly.create_cell("A")
a.add_meta_info(RBA::LayoutMetaInfo::new("am1", "u"))
ly2.create_cell("X")
b = ly2.create_cell("B")
b.add_meta_info(RBA::LayoutMetaInfo::new("bm1", "v"))
cm = RBA::CellMapping::new
cm.map(b.cell_index, a.cell_index)
assert_equal(mi2s(a), "am1:u")
ly.merge_meta_info(ly2, cm)
assert_equal(mi2s(a), "am1:u;bm1:v")
ly.copy_meta_info(ly2, cm)
assert_equal(mi2s(a), "bm1:v")
end
end end
load("test_epilogue.rb") load("test_epilogue.rb")