mirror of https://github.com/KLayout/klayout.git
commit
77232f8a50
|
|
@ -26,6 +26,8 @@
|
|||
#include "dbReader.h"
|
||||
#include "dbWriter.h"
|
||||
#include "dbSaveLayoutOptions.h"
|
||||
#include "dbRegion.h"
|
||||
#include "dbDeepShapeStore.h"
|
||||
#include "gsiExpression.h"
|
||||
#include "tlCommandLineParser.h"
|
||||
|
||||
|
|
@ -57,8 +59,8 @@ class CountingReceiver
|
|||
: public db::TileOutputReceiver
|
||||
{
|
||||
public:
|
||||
CountingReceiver ()
|
||||
: m_count (0)
|
||||
CountingReceiver (size_t *count)
|
||||
: mp_count (count)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -67,27 +69,22 @@ public:
|
|||
{
|
||||
CountingInserter inserter;
|
||||
db::insert_var (inserter, obj, tile, clip);
|
||||
m_count += inserter.count ();
|
||||
}
|
||||
|
||||
size_t count () const
|
||||
{
|
||||
return m_count;
|
||||
*mp_count += inserter.count ();
|
||||
}
|
||||
|
||||
private:
|
||||
size_t m_count;
|
||||
size_t *mp_count;
|
||||
};
|
||||
|
||||
struct ResultDescriptor
|
||||
{
|
||||
ResultDescriptor ()
|
||||
: layer_a (-1), layer_b (-1), layer_output (-1), layout (0), top_cell (0)
|
||||
: shape_count (0), layer_a (-1), layer_b (-1), layer_output (-1), layout (0), top_cell (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
tl::shared_ptr<CountingReceiver> counter;
|
||||
size_t shape_count;
|
||||
int layer_a;
|
||||
int layer_b;
|
||||
int layer_output;
|
||||
|
|
@ -97,30 +94,59 @@ struct ResultDescriptor
|
|||
size_t count () const
|
||||
{
|
||||
if (layout && layer_output >= 0) {
|
||||
// NOTE: this assumes the output is flat
|
||||
tl_assert (layout->cells () == 1);
|
||||
return layout->cell (top_cell).shapes (layer_output).size ();
|
||||
} else if (counter) {
|
||||
return counter->count ();
|
||||
size_t res = 0;
|
||||
for (db::Layout::const_iterator c = layout->begin (); c != layout->end (); ++c) {
|
||||
res += c->shapes (layer_output).size ();
|
||||
}
|
||||
return res;
|
||||
} else {
|
||||
return 0;
|
||||
return shape_count;
|
||||
}
|
||||
}
|
||||
|
||||
bool is_empty () const
|
||||
{
|
||||
if (layout && layer_output >= 0) {
|
||||
// NOTE: this assumes the output is flat
|
||||
tl_assert (layout->cells () == 1);
|
||||
return layout->cell (top_cell).shapes (layer_output).empty ();
|
||||
} else if (counter) {
|
||||
return counter->count () == 0;
|
||||
} else {
|
||||
for (db::Layout::const_iterator c = layout->begin (); c != layout->end (); ++c) {
|
||||
if (! c->shapes (layer_output).empty ()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return shape_count == 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct XORData
|
||||
{
|
||||
XORData ()
|
||||
: layout_a (0), layout_b (0), cell_a (0), cell_b (0),
|
||||
tolerance_bump (0),
|
||||
dont_summarize_missing_layers (false), silent (false), no_summary (false),
|
||||
threads (0),
|
||||
tile_size (0.0), output_layout (0), output_cell (0)
|
||||
{ }
|
||||
|
||||
db::Layout *layout_a, *layout_b;
|
||||
db::cell_index_type cell_a, cell_b;
|
||||
std::vector<double> tolerances;
|
||||
int tolerance_bump;
|
||||
bool dont_summarize_missing_layers;
|
||||
bool silent;
|
||||
bool no_summary;
|
||||
int threads;
|
||||
double tile_size;
|
||||
db::Layout *output_layout;
|
||||
db::cell_index_type output_cell;
|
||||
std::map<db::LayerProperties, std::pair<int, int> > l2l_map;
|
||||
std::map<std::pair<int, db::LayerProperties>, ResultDescriptor> *results;
|
||||
};
|
||||
|
||||
static bool run_tiled_xor (const XORData &xor_data);
|
||||
static bool run_deep_xor (const XORData &xor_data);
|
||||
|
||||
BD_PUBLIC int strmxor (int argc, char *argv[])
|
||||
{
|
||||
gsi::initialize_expressions ();
|
||||
|
|
@ -140,6 +166,7 @@ BD_PUBLIC int strmxor (int argc, char *argv[])
|
|||
bool dont_summarize_missing_layers = false;
|
||||
bool silent = false;
|
||||
bool no_summary = false;
|
||||
bool deep = false;
|
||||
std::vector<double> tolerances;
|
||||
int tolerance_bump = 10000;
|
||||
int threads = 1;
|
||||
|
|
@ -163,6 +190,10 @@ BD_PUBLIC int strmxor (int argc, char *argv[])
|
|||
<< tl::arg ("-tb|--top-b=name", &top_b, "Specifies the top cell for the second layout",
|
||||
"See --top-a for details."
|
||||
)
|
||||
<< tl::arg ("-u|--deep", &deep, "Deep (hierarchical mode)",
|
||||
"Enables hierarchical XOR (experimental). In this mode, tiling is not supported "
|
||||
"and the tiling arguments are ignored."
|
||||
)
|
||||
<< tl::arg ("-s|--silent", &silent, "Silent mode",
|
||||
"In silent mode, no summary is printed, but the exit code indicates whether "
|
||||
"the layouts are the same (0) or differences exist (> 0)."
|
||||
|
|
@ -277,135 +308,40 @@ BD_PUBLIC int strmxor (int argc, char *argv[])
|
|||
l2l_map.insert (std::make_pair (*(*l).second, std::make_pair (-1, -1))).first->second.second = (*l).first;
|
||||
}
|
||||
|
||||
db::TilingProcessor proc;
|
||||
proc.set_dbu (std::min (layout_a.dbu (), layout_b.dbu ()));
|
||||
proc.set_threads (std::max (1, threads));
|
||||
if (tile_size > db::epsilon) {
|
||||
if (tl::verbosity () >= 20) {
|
||||
tl::log << "Tile size: " << tile_size;
|
||||
}
|
||||
proc.tile_size (tile_size, tile_size);
|
||||
}
|
||||
|
||||
proc.tile_border (tolerances.back () * 2.0, tolerances.back () * 2.0);
|
||||
if (tl::verbosity () >= 20) {
|
||||
tl::log << "Tile border: " << tolerances.back () * 2.0;
|
||||
}
|
||||
|
||||
if (tl::verbosity () >= 20) {
|
||||
tl::log << "Database unit: " << proc.dbu ();
|
||||
tl::log << "Threads: " << threads;
|
||||
tl::log << "Layer bump for tolerance: " << tolerance_bump;
|
||||
}
|
||||
|
||||
std::auto_ptr<db::Layout> output_layout;
|
||||
db::cell_index_type output_top = 0;
|
||||
|
||||
if (! output.empty ()) {
|
||||
output_layout.reset (new db::Layout ());
|
||||
output_layout->dbu (proc.dbu ());
|
||||
output_top = output_layout->add_cell ("XOR");
|
||||
}
|
||||
|
||||
std::map<std::pair<int, db::LayerProperties>, ResultDescriptor> results;
|
||||
|
||||
bool result = true;
|
||||
XORData xor_data;
|
||||
xor_data.layout_a = &layout_a;
|
||||
xor_data.cell_a = index_a.second;
|
||||
xor_data.layout_b = &layout_b;
|
||||
xor_data.cell_b = index_b.second;
|
||||
xor_data.tolerances = tolerances;
|
||||
xor_data.tolerance_bump = tolerance_bump;
|
||||
xor_data.dont_summarize_missing_layers = dont_summarize_missing_layers;
|
||||
xor_data.silent = silent;
|
||||
xor_data.no_summary = no_summary;
|
||||
xor_data.threads = threads;
|
||||
xor_data.tile_size = tile_size;
|
||||
xor_data.output_layout = output_layout.get ();
|
||||
xor_data.l2l_map = l2l_map;
|
||||
xor_data.results = &results;
|
||||
|
||||
int index = 1;
|
||||
// Runs the XOR
|
||||
|
||||
for (std::map<db::LayerProperties, std::pair<int, int> >::const_iterator ll = l2l_map.begin (); ll != l2l_map.end (); ++ll) {
|
||||
bool result;
|
||||
|
||||
if ((ll->second.first < 0 || ll->second.second < 0) && ! dont_summarize_missing_layers) {
|
||||
|
||||
if (ll->second.first < 0) {
|
||||
(silent ? tl::log : tl::warn) << "Layer " << ll->first.to_string () << " is not present in first layout, but in second";
|
||||
} else {
|
||||
(silent ? tl::log : tl::warn) << "Layer " << ll->first.to_string () << " is not present in second layout, but in first";
|
||||
}
|
||||
|
||||
result = false;
|
||||
|
||||
int tol_index = 0;
|
||||
for (std::vector<double>::const_iterator t = tolerances.begin (); t != tolerances.end (); ++t) {
|
||||
|
||||
ResultDescriptor &result = results.insert (std::make_pair (std::make_pair (tol_index, ll->first), ResultDescriptor ())).first->second;
|
||||
result.layer_a = ll->second.first;
|
||||
result.layer_b = ll->second.second;
|
||||
result.layout = output_layout.get ();
|
||||
result.top_cell = output_top;
|
||||
|
||||
++tol_index;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
std::string in_a = "a" + tl::to_string (index);
|
||||
std::string in_b = "b" + tl::to_string (index);
|
||||
|
||||
if (ll->second.first < 0) {
|
||||
proc.input (in_a, db::RecursiveShapeIterator ());
|
||||
} else {
|
||||
proc.input (in_a, db::RecursiveShapeIterator (layout_a, layout_a.cell (index_a.second), ll->second.first));
|
||||
}
|
||||
|
||||
if (ll->second.second < 0) {
|
||||
proc.input (in_b, db::RecursiveShapeIterator ());
|
||||
} else {
|
||||
proc.input (in_b, db::RecursiveShapeIterator (layout_b, layout_b.cell (index_b.second), ll->second.second));
|
||||
}
|
||||
|
||||
std::string expr = "var x=" + in_a + "^" + in_b + "; ";
|
||||
|
||||
int tol_index = 0;
|
||||
for (std::vector<double>::const_iterator t = tolerances.begin (); t != tolerances.end (); ++t) {
|
||||
|
||||
std::string out = "o" + tl::to_string (index) + "_" + tl::to_string (tol_index + 1);
|
||||
|
||||
db::LayerProperties lp = ll->first;
|
||||
if (lp.layer >= 0) {
|
||||
lp.layer += tol_index * tolerance_bump;
|
||||
}
|
||||
|
||||
ResultDescriptor &result = results.insert (std::make_pair (std::make_pair (tol_index, ll->first), ResultDescriptor ())).first->second;
|
||||
result.layer_a = ll->second.first;
|
||||
result.layer_b = ll->second.second;
|
||||
result.layout = output_layout.get ();
|
||||
result.top_cell = output_top;
|
||||
|
||||
if (result.layout) {
|
||||
result.layer_output = result.layout->insert_layer (lp);
|
||||
proc.output (out, *result.layout, result.top_cell, result.layer_output);
|
||||
} else {
|
||||
CountingReceiver *counter = new CountingReceiver ();
|
||||
result.counter = counter;
|
||||
proc.output (out, 0, counter, db::ICplxTrans ());
|
||||
}
|
||||
|
||||
if (*t > db::epsilon) {
|
||||
expr += "x=x.sized(-round(" + tl::to_string (*t) + "/_dbu)/2).sized(round(" + tl::to_string (*t) + "/_dbu)/2); ";
|
||||
}
|
||||
expr += "_output(" + out + ",x); ";
|
||||
|
||||
++tol_index;
|
||||
|
||||
}
|
||||
|
||||
if (tl::verbosity () >= 20) {
|
||||
tl::log << "Running expression: '" << expr << "' for layer " << ll->first;
|
||||
}
|
||||
proc.queue (expr);
|
||||
|
||||
}
|
||||
|
||||
++index;
|
||||
|
||||
}
|
||||
|
||||
// Runs the processor
|
||||
|
||||
if ((! silent && ! no_summary) || result || output_layout.get ()) {
|
||||
proc.execute ("Running XOR");
|
||||
if (deep) {
|
||||
result = run_deep_xor (xor_data);
|
||||
} else {
|
||||
result = run_tiled_xor (xor_data);
|
||||
}
|
||||
|
||||
// Writes the output layout
|
||||
|
|
@ -421,11 +357,6 @@ BD_PUBLIC int strmxor (int argc, char *argv[])
|
|||
|
||||
}
|
||||
|
||||
// Determines the output status
|
||||
for (std::map<std::pair<int, db::LayerProperties>, ResultDescriptor>::const_iterator r = results.begin (); r != results.end () && result; ++r) {
|
||||
result = r->second.is_empty ();
|
||||
}
|
||||
|
||||
if (! silent && ! no_summary) {
|
||||
|
||||
if (result) {
|
||||
|
|
@ -476,3 +407,251 @@ BD_PUBLIC int strmxor (int argc, char *argv[])
|
|||
return result ? 0 : 1;
|
||||
}
|
||||
|
||||
|
||||
bool run_tiled_xor (const XORData &xor_data)
|
||||
{
|
||||
db::TilingProcessor proc;
|
||||
proc.set_dbu (std::min (xor_data.layout_a->dbu (), xor_data.layout_b->dbu ()));
|
||||
proc.set_threads (std::max (1, xor_data.threads));
|
||||
if (xor_data.tile_size > db::epsilon) {
|
||||
if (tl::verbosity () >= 20) {
|
||||
tl::log << "Tile size: " << xor_data.tile_size;
|
||||
}
|
||||
proc.tile_size (xor_data.tile_size, xor_data.tile_size);
|
||||
}
|
||||
|
||||
proc.tile_border (xor_data.tolerances.back () * 2.0, xor_data.tolerances.back () * 2.0);
|
||||
if (tl::verbosity () >= 20) {
|
||||
tl::log << "Tile border: " << xor_data.tolerances.back () * 2.0;
|
||||
}
|
||||
|
||||
if (tl::verbosity () >= 20) {
|
||||
tl::log << "Database unit: " << proc.dbu ();
|
||||
tl::log << "Threads: " << xor_data.threads;
|
||||
tl::log << "Layer bump for tolerance: " << xor_data.tolerance_bump;
|
||||
}
|
||||
|
||||
if (xor_data.output_layout) {
|
||||
xor_data.output_layout->dbu (proc.dbu ());
|
||||
}
|
||||
|
||||
bool result = true;
|
||||
|
||||
int index = 1;
|
||||
|
||||
std::list<tl::shared_ptr<CountingReceiver> > counters;
|
||||
|
||||
for (std::map<db::LayerProperties, std::pair<int, int> >::const_iterator ll = xor_data.l2l_map.begin (); ll != xor_data.l2l_map.end (); ++ll) {
|
||||
|
||||
if ((ll->second.first < 0 || ll->second.second < 0) && ! xor_data.dont_summarize_missing_layers) {
|
||||
|
||||
if (ll->second.first < 0) {
|
||||
(xor_data.silent ? tl::log : tl::warn) << "Layer " << ll->first.to_string () << " is not present in first layout, but in second";
|
||||
} else {
|
||||
(xor_data.silent ? tl::log : tl::warn) << "Layer " << ll->first.to_string () << " is not present in second layout, but in first";
|
||||
}
|
||||
|
||||
result = false;
|
||||
|
||||
int tol_index = 0;
|
||||
for (std::vector<double>::const_iterator t = xor_data.tolerances.begin (); t != xor_data.tolerances.end (); ++t) {
|
||||
|
||||
ResultDescriptor &result = xor_data.results->insert (std::make_pair (std::make_pair (tol_index, ll->first), ResultDescriptor ())).first->second;
|
||||
result.layer_a = ll->second.first;
|
||||
result.layer_b = ll->second.second;
|
||||
result.layout = xor_data.output_layout;
|
||||
result.top_cell = xor_data.output_cell;
|
||||
|
||||
++tol_index;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
std::string in_a = "a" + tl::to_string (index);
|
||||
std::string in_b = "b" + tl::to_string (index);
|
||||
|
||||
if (ll->second.first < 0) {
|
||||
proc.input (in_a, db::RecursiveShapeIterator ());
|
||||
} else {
|
||||
proc.input (in_a, db::RecursiveShapeIterator (*xor_data.layout_a, xor_data.layout_a->cell (xor_data.cell_a), ll->second.first));
|
||||
}
|
||||
|
||||
if (ll->second.second < 0) {
|
||||
proc.input (in_b, db::RecursiveShapeIterator ());
|
||||
} else {
|
||||
proc.input (in_b, db::RecursiveShapeIterator (*xor_data.layout_b, xor_data.layout_b->cell (xor_data.cell_b), ll->second.second));
|
||||
}
|
||||
|
||||
std::string expr = "var x=" + in_a + "^" + in_b + "; ";
|
||||
|
||||
int tol_index = 0;
|
||||
for (std::vector<double>::const_iterator t = xor_data.tolerances.begin (); t != xor_data.tolerances.end (); ++t) {
|
||||
|
||||
std::string out = "o" + tl::to_string (index) + "_" + tl::to_string (tol_index + 1);
|
||||
|
||||
db::LayerProperties lp = ll->first;
|
||||
if (lp.layer >= 0) {
|
||||
lp.layer += tol_index * xor_data.tolerance_bump;
|
||||
}
|
||||
|
||||
ResultDescriptor &result = xor_data.results->insert (std::make_pair (std::make_pair (tol_index, ll->first), ResultDescriptor ())).first->second;
|
||||
result.layer_a = ll->second.first;
|
||||
result.layer_b = ll->second.second;
|
||||
result.layout = xor_data.output_layout;
|
||||
result.top_cell = xor_data.output_cell;
|
||||
|
||||
if (result.layout) {
|
||||
result.layer_output = result.layout->insert_layer (lp);
|
||||
proc.output (out, *result.layout, result.top_cell, result.layer_output);
|
||||
} else {
|
||||
CountingReceiver *counter = new CountingReceiver (&result.shape_count);
|
||||
counters.push_back (tl::shared_ptr<CountingReceiver> (counter));
|
||||
proc.output (out, 0, counter, db::ICplxTrans ());
|
||||
}
|
||||
|
||||
if (*t > db::epsilon) {
|
||||
expr += "x=x.sized(-round(" + tl::to_string (*t) + "/_dbu)/2).sized(round(" + tl::to_string (*t) + "/_dbu)/2); ";
|
||||
}
|
||||
expr += "_output(" + out + ",x); ";
|
||||
|
||||
++tol_index;
|
||||
|
||||
}
|
||||
|
||||
if (tl::verbosity () >= 20) {
|
||||
tl::log << "Running expression: '" << expr << "' for layer " << ll->first;
|
||||
}
|
||||
proc.queue (expr);
|
||||
|
||||
}
|
||||
|
||||
++index;
|
||||
|
||||
}
|
||||
|
||||
// Runs the processor
|
||||
|
||||
if ((! xor_data.silent && ! xor_data.no_summary) || result || xor_data.output_layout) {
|
||||
proc.execute ("Running XOR");
|
||||
}
|
||||
|
||||
// Determines the output status
|
||||
for (std::map<std::pair<int, db::LayerProperties>, ResultDescriptor>::const_iterator r = xor_data.results->begin (); r != xor_data.results->end () && result; ++r) {
|
||||
result = r->second.is_empty ();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool run_deep_xor (const XORData &xor_data)
|
||||
{
|
||||
db::DeepShapeStore dss;
|
||||
dss.set_threads (xor_data.threads);
|
||||
|
||||
double dbu = std::min (xor_data.layout_a->dbu (), xor_data.layout_b->dbu ());
|
||||
|
||||
if (tl::verbosity () >= 20) {
|
||||
tl::log << "Database unit: " << dbu;
|
||||
tl::log << "Threads: " << xor_data.threads;
|
||||
tl::log << "Layer bump for tolerance: " << xor_data.tolerance_bump;
|
||||
}
|
||||
|
||||
if (xor_data.output_layout) {
|
||||
xor_data.output_layout->dbu (dbu);
|
||||
}
|
||||
|
||||
bool result = true;
|
||||
|
||||
int index = 1;
|
||||
|
||||
for (std::map<db::LayerProperties, std::pair<int, int> >::const_iterator ll = xor_data.l2l_map.begin (); ll != xor_data.l2l_map.end (); ++ll) {
|
||||
|
||||
if ((ll->second.first < 0 || ll->second.second < 0) && ! xor_data.dont_summarize_missing_layers) {
|
||||
|
||||
if (ll->second.first < 0) {
|
||||
(xor_data.silent ? tl::log : tl::warn) << "Layer " << ll->first.to_string () << " is not present in first layout, but in second";
|
||||
} else {
|
||||
(xor_data.silent ? tl::log : tl::warn) << "Layer " << ll->first.to_string () << " is not present in second layout, but in first";
|
||||
}
|
||||
|
||||
result = false;
|
||||
|
||||
int tol_index = 0;
|
||||
for (std::vector<double>::const_iterator t = xor_data.tolerances.begin (); t != xor_data.tolerances.end (); ++t) {
|
||||
|
||||
ResultDescriptor &result = xor_data.results->insert (std::make_pair (std::make_pair (tol_index, ll->first), ResultDescriptor ())).first->second;
|
||||
result.layer_a = ll->second.first;
|
||||
result.layer_b = ll->second.second;
|
||||
result.layout = xor_data.output_layout;
|
||||
result.top_cell = xor_data.output_cell;
|
||||
|
||||
++tol_index;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
db::RecursiveShapeIterator ri_a, ri_b;
|
||||
|
||||
if (ll->second.first >= 0) {
|
||||
ri_a = db::RecursiveShapeIterator (*xor_data.layout_a, xor_data.layout_a->cell (xor_data.cell_a), ll->second.first);
|
||||
}
|
||||
|
||||
if (ll->second.second >= 0) {
|
||||
ri_b = db::RecursiveShapeIterator (*xor_data.layout_b, xor_data.layout_b->cell (xor_data.cell_b), ll->second.second);
|
||||
}
|
||||
|
||||
db::Region in_a (ri_a, dss, db::ICplxTrans (xor_data.layout_a->dbu () / dbu));
|
||||
db::Region in_b (ri_b, dss, db::ICplxTrans (xor_data.layout_b->dbu () / dbu));
|
||||
|
||||
db::Region xor_res;
|
||||
xor_res = in_a ^ in_b;
|
||||
|
||||
int tol_index = 0;
|
||||
for (std::vector<double>::const_iterator t = xor_data.tolerances.begin (); t != xor_data.tolerances.end (); ++t) {
|
||||
|
||||
if (tl::verbosity () >= 20) {
|
||||
tl::log << "Running XOR on layer " << ll->first.to_string () << " with tolerance " << *t;
|
||||
}
|
||||
|
||||
db::LayerProperties lp = ll->first;
|
||||
if (lp.layer >= 0) {
|
||||
lp.layer += tol_index * xor_data.tolerance_bump;
|
||||
}
|
||||
|
||||
ResultDescriptor &result = xor_data.results->insert (std::make_pair (std::make_pair (tol_index, ll->first), ResultDescriptor ())).first->second;
|
||||
result.layer_a = ll->second.first;
|
||||
result.layer_b = ll->second.second;
|
||||
result.layout = xor_data.output_layout;
|
||||
result.top_cell = xor_data.output_cell;
|
||||
|
||||
if (*t > db::epsilon) {
|
||||
xor_res.size (-db::coord_traits<db::Coord>::rounded (0.5 * *t / dbu));
|
||||
xor_res.size (db::coord_traits<db::Coord>::rounded (0.5 * *t / dbu));
|
||||
}
|
||||
|
||||
if (xor_data.output_layout) {
|
||||
result.layer_output = result.layout->insert_layer (lp);
|
||||
xor_res.insert_into (xor_data.output_layout, xor_data.output_cell, result.layer_output);
|
||||
} else {
|
||||
result.shape_count = xor_res.size ();
|
||||
}
|
||||
|
||||
++tol_index;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
++index;
|
||||
|
||||
}
|
||||
|
||||
// Determines the output status
|
||||
for (std::map<std::pair<int, db::LayerProperties>, ResultDescriptor>::const_iterator r = xor_data.results->begin (); r != xor_data.results->end () && result; ++r) {
|
||||
result = r->second.is_empty ();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
BD_PUBLIC int strmxor (int argc, char *argv[]);
|
||||
|
||||
TEST(0)
|
||||
TEST(0_Basic_Flat)
|
||||
{
|
||||
tl::CaptureChannel cap;
|
||||
|
||||
|
|
@ -51,7 +51,28 @@ TEST(0)
|
|||
);
|
||||
}
|
||||
|
||||
TEST(1A)
|
||||
TEST(0_Basic_Deep)
|
||||
{
|
||||
tl::CaptureChannel cap;
|
||||
|
||||
std::string input_a = tl::testsrc ();
|
||||
input_a += "/testdata/bd/strmxor_in1.gds";
|
||||
|
||||
std::string input_b = tl::testsrc ();
|
||||
input_b += "/testdata/bd/strmxor_in1.gds";
|
||||
|
||||
std::string output = this->tmp_file ("tmp.oas");
|
||||
|
||||
const char *argv[] = { "x", "-u", input_a.c_str (), input_b.c_str () };
|
||||
|
||||
EXPECT_EQ (strmxor (sizeof (argv) / sizeof (argv[0]), (char **) argv), 0);
|
||||
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
"No differences found\n"
|
||||
);
|
||||
}
|
||||
|
||||
TEST(1A_Flat)
|
||||
{
|
||||
tl::CaptureChannel cap;
|
||||
|
||||
|
|
@ -93,7 +114,49 @@ TEST(1A)
|
|||
);
|
||||
}
|
||||
|
||||
TEST(1B)
|
||||
TEST(1A_Deep)
|
||||
{
|
||||
tl::CaptureChannel cap;
|
||||
|
||||
std::string input_a = tl::testsrc ();
|
||||
input_a += "/testdata/bd/strmxor_in1.gds";
|
||||
|
||||
std::string input_b = tl::testsrc ();
|
||||
input_b += "/testdata/bd/strmxor_in2.gds";
|
||||
|
||||
std::string au = tl::testsrc ();
|
||||
au += "/testdata/bd/strmxor_au1d.oas";
|
||||
|
||||
std::string output = this->tmp_file ("tmp.oas");
|
||||
|
||||
const char *argv[] = { "x", "--deep", input_a.c_str (), input_b.c_str (), output.c_str () };
|
||||
|
||||
EXPECT_EQ (strmxor (sizeof (argv) / sizeof (argv[0]), (char **) argv), 1);
|
||||
|
||||
db::Layout layout;
|
||||
|
||||
{
|
||||
tl::InputStream stream (output);
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
"Layer 10/0 is not present in first layout, but in second\n"
|
||||
"Result summary (layers without differences are not shown):\n"
|
||||
"\n"
|
||||
" Layer Output Differences (shape count)\n"
|
||||
" -------------------------------------------------------\n"
|
||||
" 3/0 3/0 3\n"
|
||||
" 6/0 6/0 314\n"
|
||||
" 8/1 8/1 1\n"
|
||||
" 10/0 - (no such layer in first layout)\n"
|
||||
"\n"
|
||||
);
|
||||
}
|
||||
|
||||
TEST(1B_Flat)
|
||||
{
|
||||
tl::CaptureChannel cap;
|
||||
|
||||
|
|
@ -123,7 +186,37 @@ TEST(1B)
|
|||
);
|
||||
}
|
||||
|
||||
TEST(1C)
|
||||
TEST(1B_Deep)
|
||||
{
|
||||
tl::CaptureChannel cap;
|
||||
|
||||
std::string input_a = tl::testsrc ();
|
||||
input_a += "/testdata/bd/strmxor_in1.gds";
|
||||
|
||||
std::string input_b = tl::testsrc ();
|
||||
input_b += "/testdata/bd/strmxor_in2.gds";
|
||||
|
||||
std::string output = this->tmp_file ("tmp.oas");
|
||||
|
||||
const char *argv[] = { "x", "-u", input_a.c_str (), input_b.c_str () };
|
||||
|
||||
EXPECT_EQ (strmxor (sizeof (argv) / sizeof (argv[0]), (char **) argv), 1);
|
||||
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
"Layer 10/0 is not present in first layout, but in second\n"
|
||||
"Result summary (layers without differences are not shown):\n"
|
||||
"\n"
|
||||
" Layer Output Differences (shape count)\n"
|
||||
" -------------------------------------------------------\n"
|
||||
" 3/0 - 30\n"
|
||||
" 6/0 - 314\n"
|
||||
" 8/1 - 1\n"
|
||||
" 10/0 - (no such layer in first layout)\n"
|
||||
"\n"
|
||||
);
|
||||
}
|
||||
|
||||
TEST(1C_Flat)
|
||||
{
|
||||
tl::CaptureChannel cap;
|
||||
|
||||
|
|
@ -144,7 +237,28 @@ TEST(1C)
|
|||
);
|
||||
}
|
||||
|
||||
TEST(1D)
|
||||
TEST(1C_Deep)
|
||||
{
|
||||
tl::CaptureChannel cap;
|
||||
|
||||
std::string input_a = tl::testsrc ();
|
||||
input_a += "/testdata/bd/strmxor_in1.gds";
|
||||
|
||||
std::string input_b = tl::testsrc ();
|
||||
input_b += "/testdata/bd/strmxor_in2.gds";
|
||||
|
||||
std::string output = this->tmp_file ("tmp.oas");
|
||||
|
||||
const char *argv[] = { "x", "-u", "--no-summary", input_a.c_str (), input_b.c_str () };
|
||||
|
||||
EXPECT_EQ (strmxor (sizeof (argv) / sizeof (argv[0]), (char **) argv), 1);
|
||||
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
"Layer 10/0 is not present in first layout, but in second\n"
|
||||
);
|
||||
}
|
||||
|
||||
TEST(1D_Flat)
|
||||
{
|
||||
tl::CaptureChannel cap;
|
||||
|
||||
|
|
@ -162,7 +276,25 @@ TEST(1D)
|
|||
EXPECT_EQ (cap.captured_text (), "");
|
||||
}
|
||||
|
||||
TEST(2)
|
||||
TEST(1D_Deep)
|
||||
{
|
||||
tl::CaptureChannel cap;
|
||||
|
||||
std::string input_a = tl::testsrc ();
|
||||
input_a += "/testdata/bd/strmxor_in1.gds";
|
||||
|
||||
std::string input_b = tl::testsrc ();
|
||||
input_b += "/testdata/bd/strmxor_in2.gds";
|
||||
|
||||
std::string output = this->tmp_file ("tmp.oas");
|
||||
|
||||
const char *argv[] = { "x", "-u", "-s", input_a.c_str (), input_b.c_str () };
|
||||
|
||||
EXPECT_EQ (strmxor (sizeof (argv) / sizeof (argv[0]), (char **) argv), 1);
|
||||
EXPECT_EQ (cap.captured_text (), "");
|
||||
}
|
||||
|
||||
TEST(2_Flat)
|
||||
{
|
||||
tl::CaptureChannel cap;
|
||||
|
||||
|
|
@ -195,7 +327,40 @@ TEST(2)
|
|||
);
|
||||
}
|
||||
|
||||
TEST(3)
|
||||
TEST(2_Deep)
|
||||
{
|
||||
tl::CaptureChannel cap;
|
||||
|
||||
std::string input_a = tl::testsrc ();
|
||||
input_a += "/testdata/bd/strmxor_in1.gds";
|
||||
|
||||
std::string input_b = tl::testsrc ();
|
||||
input_b += "/testdata/bd/strmxor_in2.gds";
|
||||
|
||||
std::string au = tl::testsrc ();
|
||||
au += "/testdata/bd/strmxor_au2d.oas";
|
||||
|
||||
std::string output = this->tmp_file ("tmp.oas");
|
||||
|
||||
const char *argv[] = { "x", "-u", "--no-summary", "-l", input_a.c_str (), input_b.c_str (), output.c_str () };
|
||||
|
||||
EXPECT_EQ (strmxor (sizeof (argv) / sizeof (argv[0]), (char **) argv), 1);
|
||||
|
||||
db::Layout layout;
|
||||
|
||||
{
|
||||
tl::InputStream stream (output);
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
TEST(3_Flat)
|
||||
{
|
||||
tl::CaptureChannel cap;
|
||||
|
||||
|
|
@ -228,7 +393,41 @@ TEST(3)
|
|||
);
|
||||
}
|
||||
|
||||
TEST(4)
|
||||
TEST(3_Deep)
|
||||
{
|
||||
tl::CaptureChannel cap;
|
||||
|
||||
std::string input_a = tl::testsrc ();
|
||||
input_a += "/testdata/bd/strmxor_in1.gds";
|
||||
|
||||
std::string input_b = tl::testsrc ();
|
||||
input_b += "/testdata/bd/strmxor_in2.gds";
|
||||
|
||||
std::string au = tl::testsrc ();
|
||||
au += "/testdata/bd/strmxor_au3d.oas";
|
||||
|
||||
std::string output = this->tmp_file ("tmp.oas");
|
||||
|
||||
// NOTE: -p is ignored in deep mode
|
||||
const char *argv[] = { "x", "-u", "--no-summary", "-p=1.0", "-n=4", input_a.c_str (), input_b.c_str (), output.c_str () };
|
||||
|
||||
EXPECT_EQ (strmxor (sizeof (argv) / sizeof (argv[0]), (char **) argv), 1);
|
||||
|
||||
db::Layout layout;
|
||||
|
||||
{
|
||||
tl::InputStream stream (output);
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
"Layer 10/0 is not present in first layout, but in second\n"
|
||||
);
|
||||
}
|
||||
|
||||
TEST(4_Flat)
|
||||
{
|
||||
tl::CaptureChannel cap;
|
||||
|
||||
|
|
@ -261,7 +460,40 @@ TEST(4)
|
|||
);
|
||||
}
|
||||
|
||||
TEST(5)
|
||||
TEST(4_Deep)
|
||||
{
|
||||
tl::CaptureChannel cap;
|
||||
|
||||
std::string input_a = tl::testsrc ();
|
||||
input_a += "/testdata/bd/strmxor_in1.gds";
|
||||
|
||||
std::string input_b = tl::testsrc ();
|
||||
input_b += "/testdata/bd/strmxor_in2.gds";
|
||||
|
||||
std::string au = tl::testsrc ();
|
||||
au += "/testdata/bd/strmxor_au4d.oas";
|
||||
|
||||
std::string output = this->tmp_file ("tmp.oas");
|
||||
|
||||
const char *argv[] = { "x", "-u", "--no-summary", "-p=1.0", "-n=4", "-t=0.0,0.005,0.01,0.02,0.09,0.1", input_a.c_str (), input_b.c_str (), output.c_str () };
|
||||
|
||||
EXPECT_EQ (strmxor (sizeof (argv) / sizeof (argv[0]), (char **) argv), 1);
|
||||
|
||||
db::Layout layout;
|
||||
|
||||
{
|
||||
tl::InputStream stream (output);
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
"Layer 10/0 is not present in first layout, but in second\n"
|
||||
);
|
||||
}
|
||||
|
||||
TEST(5_Flat)
|
||||
{
|
||||
tl::CaptureChannel cap;
|
||||
|
||||
|
|
@ -294,7 +526,40 @@ TEST(5)
|
|||
);
|
||||
}
|
||||
|
||||
TEST(6)
|
||||
TEST(5_Deep)
|
||||
{
|
||||
tl::CaptureChannel cap;
|
||||
|
||||
std::string input_a = tl::testsrc ();
|
||||
input_a += "/testdata/bd/strmxor_in1.gds";
|
||||
|
||||
std::string input_b = tl::testsrc ();
|
||||
input_b += "/testdata/bd/strmxor_in2.gds";
|
||||
|
||||
std::string au = tl::testsrc ();
|
||||
au += "/testdata/bd/strmxor_au5d.oas";
|
||||
|
||||
std::string output = this->tmp_file ("tmp.oas");
|
||||
|
||||
const char *argv[] = { "x", "-u", "--no-summary", "-b=1000", "-t=0.0,0.005,0.01,0.02,0.09,0.1", input_a.c_str (), input_b.c_str (), output.c_str () };
|
||||
|
||||
EXPECT_EQ (strmxor (sizeof (argv) / sizeof (argv[0]), (char **) argv), 1);
|
||||
|
||||
db::Layout layout;
|
||||
|
||||
{
|
||||
tl::InputStream stream (output);
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
"Layer 10/0 is not present in first layout, but in second\n"
|
||||
);
|
||||
}
|
||||
|
||||
TEST(6_Flat)
|
||||
{
|
||||
tl::CaptureChannel cap;
|
||||
|
||||
|
|
@ -326,3 +591,36 @@ TEST(6)
|
|||
"Layer 10/0 is not present in first layout, but in second\n"
|
||||
);
|
||||
}
|
||||
|
||||
TEST(6_Deep)
|
||||
{
|
||||
tl::CaptureChannel cap;
|
||||
|
||||
std::string input_a = tl::testsrc ();
|
||||
input_a += "/testdata/bd/strmxor_in1.gds";
|
||||
|
||||
std::string input_b = tl::testsrc ();
|
||||
input_b += "/testdata/bd/strmxor_in2.gds";
|
||||
|
||||
std::string au = tl::testsrc ();
|
||||
au += "/testdata/bd/strmxor_au6d.oas";
|
||||
|
||||
std::string output = this->tmp_file ("tmp.oas");
|
||||
|
||||
const char *argv[] = { "x", "-u", "--no-summary", "-ta=INV2", "-tb=2VNI", input_a.c_str (), input_b.c_str (), output.c_str () };
|
||||
|
||||
EXPECT_EQ (strmxor (sizeof (argv) / sizeof (argv[0]), (char **) argv), 1);
|
||||
|
||||
db::Layout layout;
|
||||
|
||||
{
|
||||
tl::InputStream stream (output);
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
"Layer 10/0 is not present in first layout, but in second\n"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -231,19 +231,78 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="2">
|
||||
<widget class="QCheckBox" name="axorb_cb">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<item row="5" column="2">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>A XOR B (differences)</string>
|
||||
<string>Tolerances (t1,t2,..) in micron</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Threads</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1" colspan="2">
|
||||
<widget class="QFrame" name="frame_2">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="threads">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Used for tiles and layers</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Tolerances</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Compare modes </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -263,6 +322,22 @@
|
|||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="2">
|
||||
<widget class="QCheckBox" name="axorb_cb">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>A XOR B (differences)</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1" colspan="2">
|
||||
<widget class="QCheckBox" name="summarize_cb">
|
||||
<property name="text">
|
||||
|
|
@ -273,42 +348,27 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Tolerances</string>
|
||||
<item row="2" column="1" colspan="2">
|
||||
<widget class="QCheckBox" name="bnota_cb">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Compare modes </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="2">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Tolerances (t1,t2,..) in micron</string>
|
||||
<string>B NOT A (in B but not in A)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Threads</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Tiling</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1" colspan="2">
|
||||
<item row="7" column="1" colspan="2">
|
||||
<widget class="QFrame" name="frame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
|
|
@ -365,66 +425,6 @@
|
|||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1" colspan="2">
|
||||
<widget class="QFrame" name="frame_2">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="threads">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Used for tiles and layers</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1" colspan="2">
|
||||
<widget class="QCheckBox" name="bnota_cb">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>B NOT A (in B but not in A)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QLineEdit" name="tolerances">
|
||||
<property name="sizePolicy">
|
||||
|
|
@ -435,6 +435,20 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_14">
|
||||
<property name="text">
|
||||
<string>Hierarchical</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1" colspan="2">
|
||||
<widget class="QCheckBox" name="deep">
|
||||
<property name="text">
|
||||
<string>consider hierarchy (experimental)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
|||
|
|
@ -25,11 +25,13 @@
|
|||
#include "layXORProgress.h"
|
||||
#include "antService.h"
|
||||
#include "rdb.h"
|
||||
#include "rdbUtils.h"
|
||||
#include "dbShapeProcessor.h"
|
||||
#include "dbRecursiveShapeIterator.h"
|
||||
#include "dbClip.h"
|
||||
#include "dbLayoutUtils.h"
|
||||
#include "dbRegion.h"
|
||||
#include "dbDeepShapeStore.h"
|
||||
#include "tlTimer.h"
|
||||
#include "tlProgress.h"
|
||||
#include "tlThreadedWorkers.h"
|
||||
|
|
@ -58,6 +60,7 @@ std::string cfg_xor_anotb ("xor-anotb");
|
|||
std::string cfg_xor_bnota ("xor-bnota");
|
||||
std::string cfg_xor_summarize ("xor-summarize");
|
||||
std::string cfg_xor_tolerances ("xor-tolerances");
|
||||
std::string cfg_xor_deep ("xor-deep");
|
||||
std::string cfg_xor_tiling ("xor-tiling");
|
||||
std::string cfg_xor_tiling_heal ("xor-tiling-heal");
|
||||
std::string cfg_xor_region_mode ("xor-region-mode");
|
||||
|
|
@ -169,6 +172,7 @@ XORToolDialog::XORToolDialog (QWidget *parent)
|
|||
|
||||
connect (mp_ui->input_layers_cbx, SIGNAL (currentIndexChanged (int)), this, SLOT (input_changed (int)));
|
||||
connect (mp_ui->output_cbx, SIGNAL (currentIndexChanged (int)), this, SLOT (output_changed (int)));
|
||||
connect (mp_ui->deep, SIGNAL (clicked ()), this, SLOT (deep_changed ()));
|
||||
|
||||
input_changed (0);
|
||||
output_changed (0);
|
||||
|
|
@ -251,6 +255,12 @@ XORToolDialog::exec_dialog (lay::LayoutView *view)
|
|||
mp_ui->tolerances->setText (tl::to_qstring (tol));
|
||||
}
|
||||
|
||||
bool deep = false;
|
||||
if (config_root->config_get (cfg_xor_deep, deep)) {
|
||||
mp_ui->deep->setChecked (deep);
|
||||
}
|
||||
deep_changed ();
|
||||
|
||||
std::string tiling;
|
||||
if (config_root->config_get (cfg_xor_tiling, tiling)) {
|
||||
mp_ui->tiling->setText (tl::to_qstring (tiling));
|
||||
|
|
@ -335,6 +345,7 @@ BEGIN_PROTECTED
|
|||
config_root->config_set (cfg_xor_layer_offset, tl::to_string (mp_ui->layer_offset_le->text ()));
|
||||
config_root->config_set (cfg_xor_summarize, mp_ui->summarize_cb->isChecked ());
|
||||
config_root->config_set (cfg_xor_tolerances, tl::to_string (mp_ui->tolerances->text ()));
|
||||
config_root->config_set (cfg_xor_deep, mp_ui->deep->isChecked ());
|
||||
config_root->config_set (cfg_xor_tiling, tl::to_string (mp_ui->tiling->text ()));
|
||||
config_root->config_set (cfg_xor_tiling_heal, mp_ui->heal_cb->isChecked ());
|
||||
config_root->config_end ();
|
||||
|
|
@ -344,6 +355,14 @@ BEGIN_PROTECTED
|
|||
END_PROTECTED
|
||||
}
|
||||
|
||||
void
|
||||
XORToolDialog::deep_changed ()
|
||||
{
|
||||
bool deep = mp_ui->deep->isChecked ();
|
||||
mp_ui->tiling->setEnabled (!deep);
|
||||
mp_ui->heal_cb->setEnabled (!deep);
|
||||
}
|
||||
|
||||
void
|
||||
XORToolDialog::input_changed (int /*index*/)
|
||||
{
|
||||
|
|
@ -510,6 +529,28 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void issue_region (unsigned int tol_index, unsigned int layer_index, const db::Region ®ion)
|
||||
{
|
||||
QMutexLocker locker (&m_mutex);
|
||||
db::CplxTrans trans (dbu ());
|
||||
|
||||
if (m_output_mode == OMMarkerDatabase) {
|
||||
|
||||
rdb::Category *layercat = m_layer_categories[tol_index][layer_index];
|
||||
|
||||
std::pair<db::RecursiveShapeIterator, db::ICplxTrans> it = region.begin_iter ();
|
||||
rdb::scan_layer (layercat, m_rdb_cell, trans * it.second, it.first, false);
|
||||
|
||||
} else {
|
||||
|
||||
db::Cell *output_cell = m_sub_cells[tol_index];
|
||||
unsigned int output_layer = m_sub_output_layers[tol_index][layer_index];
|
||||
|
||||
region.insert_into (output_cell->layout (), output_cell->cell_index (), output_layer);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void issue_polygon (unsigned int tol_index, unsigned int layer_index, const db::Polygon &polygon, bool touches_border = false)
|
||||
{
|
||||
QMutexLocker locker (&m_mutex);
|
||||
|
|
@ -588,12 +629,17 @@ class XORTask
|
|||
: public tl::Task
|
||||
{
|
||||
public:
|
||||
XORTask (const std::string &tile_desc, const db::Box &clip_box, const db::Box ®ion_a, const db::Box ®ion_b, unsigned int layer_index, const db::LayerProperties &lp, const std::vector<unsigned int> &la, const std::vector<unsigned int> &lb, int ix, int iy)
|
||||
: m_tile_desc (tile_desc), m_clip_box (clip_box), m_region_a (region_a), m_region_b (region_b), m_layer_index (layer_index), m_lp (lp), m_la (la), m_lb (lb), m_ix (ix), m_iy (iy)
|
||||
XORTask (bool deep, const std::string &tile_desc, const db::Box &clip_box, const db::Box ®ion_a, const db::Box ®ion_b, unsigned int layer_index, const db::LayerProperties &lp, const std::vector<unsigned int> &la, const std::vector<unsigned int> &lb, int ix, int iy)
|
||||
: m_deep (deep), m_tile_desc (tile_desc), m_clip_box (clip_box), m_region_a (region_a), m_region_b (region_b), m_layer_index (layer_index), m_lp (lp), m_la (la), m_lb (lb), m_ix (ix), m_iy (iy)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
bool deep () const
|
||||
{
|
||||
return m_deep;
|
||||
}
|
||||
|
||||
const std::string &tile_desc () const
|
||||
{
|
||||
return m_tile_desc;
|
||||
|
|
@ -645,6 +691,7 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
bool m_deep;
|
||||
std::string m_tile_desc;
|
||||
db::Box m_clip_box, m_region_a, m_region_b;
|
||||
unsigned int m_layer_index;
|
||||
|
|
@ -675,10 +722,117 @@ private:
|
|||
XORJob *mp_job;
|
||||
|
||||
void do_perform (const XORTask *task);
|
||||
void do_perform_tiled (const XORTask *task);
|
||||
void do_perform_deep (const XORTask *task);
|
||||
};
|
||||
|
||||
void
|
||||
XORWorker::do_perform (const XORTask *xor_task)
|
||||
{
|
||||
if (xor_task->deep ()) {
|
||||
do_perform_deep (xor_task);
|
||||
} else {
|
||||
do_perform_tiled (xor_task);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
XORWorker::do_perform_deep (const XORTask *xor_task)
|
||||
{
|
||||
db::DeepShapeStore dss;
|
||||
db::Region rr;
|
||||
|
||||
unsigned int tol_index = 0;
|
||||
for (std::vector <db::Coord>::const_iterator t = mp_job->tolerances ().begin (); t != mp_job->tolerances ().end (); ++t, ++tol_index) {
|
||||
|
||||
const std::vector<unsigned int> &la = xor_task->la ();
|
||||
const std::vector<unsigned int> &lb = xor_task->lb ();
|
||||
|
||||
if ((!la.empty () && !lb.empty ()) || mp_job->el_handling () != XORJob::EL_summarize) {
|
||||
|
||||
if (tl::verbosity () >= 10) {
|
||||
tl::info << "XOR tool (hierarchical): layer " << xor_task->lp ().to_string () << ", tolerance " << *t * mp_job->dbu ();
|
||||
}
|
||||
|
||||
tl::SelfTimer timer (tl::verbosity () >= 11, "Elapsed time");
|
||||
|
||||
if (tol_index == 0) {
|
||||
|
||||
if ((!la.empty () && !lb.empty ()) || mp_job->el_handling () == XORJob::EL_process) {
|
||||
|
||||
tl::SelfTimer timer (tl::verbosity () >= 21, "Boolean part");
|
||||
|
||||
db::RecursiveShapeIterator s_a (mp_job->cva ()->layout (), mp_job->cva ()->layout ().cell (mp_job->cva ().cell_index ()), la, xor_task->region_a ());
|
||||
db::RecursiveShapeIterator s_b (mp_job->cvb ()->layout (), mp_job->cvb ()->layout ().cell (mp_job->cvb ().cell_index ()), lb, xor_task->region_b ());
|
||||
|
||||
db::Region ra (s_a, dss, db::ICplxTrans (mp_job->cva ()->layout ().dbu () / mp_job->dbu ()));
|
||||
db::Region rb (s_b, dss, db::ICplxTrans (mp_job->cvb ()->layout ().dbu () / mp_job->dbu ()));
|
||||
|
||||
if (mp_job->op () == db::BooleanOp::Xor) {
|
||||
rr = ra ^ rb;
|
||||
} else if (mp_job->op () == db::BooleanOp::ANotB) {
|
||||
rr = ra - rb;
|
||||
} else if (mp_job->op () == db::BooleanOp::BNotA) {
|
||||
rr = rb - ra;
|
||||
}
|
||||
|
||||
} else if (mp_job->op () == db::BooleanOp::Xor ||
|
||||
(mp_job->op () == db::BooleanOp::ANotB && !la.empty ()) ||
|
||||
(mp_job->op () == db::BooleanOp::BNotA && !lb.empty ())) {
|
||||
|
||||
tl::SelfTimer timer (tl::verbosity () >= 21, "Boolean part (shortcut)");
|
||||
|
||||
db::RecursiveShapeIterator s;
|
||||
db::ICplxTrans dbu_scale;
|
||||
|
||||
if (!la.empty ()) {
|
||||
s = db::RecursiveShapeIterator (mp_job->cva ()->layout (), *mp_job->cva ().cell (), la, xor_task->region_a ());
|
||||
dbu_scale = db::ICplxTrans (mp_job->cva ()->layout ().dbu () / mp_job->dbu ());
|
||||
} else if (!lb.empty ()) {
|
||||
s = db::RecursiveShapeIterator (mp_job->cvb ()->layout (), *mp_job->cvb ().cell (), lb, xor_task->region_b ());
|
||||
dbu_scale = db::ICplxTrans (mp_job->cvb ()->layout ().dbu () / mp_job->dbu ());
|
||||
}
|
||||
|
||||
rr = db::Region (s, dss, dbu_scale);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (*t > 0) {
|
||||
tl::SelfTimer timer (tl::verbosity () >= 21, "Sizing part");
|
||||
rr.size (-((*t + 1) / 2), (unsigned int)2, false);
|
||||
rr.size (((*t + 1) / 2), (unsigned int)2, false);
|
||||
}
|
||||
|
||||
// TODO: no clipping for hieararchical mode yet
|
||||
mp_job->issue_region (tol_index, xor_task->layer_index (), rr);
|
||||
|
||||
mp_job->add_results (xor_task->lp (), *t, rr.size (), xor_task->ix (), xor_task->iy ());
|
||||
|
||||
} else if (mp_job->op () == db::BooleanOp::Xor ||
|
||||
(mp_job->op () == db::BooleanOp::ANotB && !la.empty ()) ||
|
||||
(mp_job->op () == db::BooleanOp::BNotA && !lb.empty ())) {
|
||||
|
||||
if (!la.empty ()) {
|
||||
mp_job->issue_string (tol_index, xor_task->layer_index (), tl::to_string (QObject::tr ("Layer not present at all in layout B")));
|
||||
mp_job->add_results (xor_task->lp (), *t, missing_in_b, 0, 0);
|
||||
}
|
||||
|
||||
if (!lb.empty ()) {
|
||||
mp_job->issue_string (tol_index, xor_task->layer_index (), tl::to_string (QObject::tr ("Layer not present at all in layout A")));
|
||||
mp_job->add_results (xor_task->lp (), *t, missing_in_a, 0, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
mp_job->next_progress ();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
XORWorker::do_perform_tiled (const XORTask *xor_task)
|
||||
{
|
||||
db::ShapeProcessor sp (true);
|
||||
|
||||
|
|
@ -927,6 +1081,8 @@ XORToolDialog::run_xor ()
|
|||
bool anotb = mp_ui->anotb_cb->isChecked ();
|
||||
bool bnota = mp_ui->bnota_cb->isChecked ();
|
||||
|
||||
bool deep = mp_ui->deep->isChecked ();
|
||||
|
||||
bool summarize = mp_ui->summarize_cb->isChecked ();
|
||||
// TODO: make this a user interface feature later
|
||||
bool process_el = lay::ApplicationBase::instance ()->special_app_flag ("ALWAYS_DO_XOR");
|
||||
|
|
@ -1018,7 +1174,7 @@ XORToolDialog::run_xor ()
|
|||
double tile_size = 0; // in micron units
|
||||
bool tile_heal = mp_ui->heal_cb->isChecked ();
|
||||
|
||||
{
|
||||
if (! deep) {
|
||||
std::string text (tl::to_string (mp_ui->tiling->text ()));
|
||||
tl::Extractor ex (text.c_str ());
|
||||
double t = 0.0;
|
||||
|
|
@ -1357,7 +1513,7 @@ XORToolDialog::run_xor ()
|
|||
|
||||
unsigned int layer_index = 0;
|
||||
for (std::map<db::LayerProperties, std::pair<std::vector<unsigned int>, std::vector<unsigned int> >, db::LPLogicalLessFunc>::const_iterator l = layers.begin (); l != layers.end (); ++l, ++layer_index) {
|
||||
job.schedule (new XORTask (tile_desc, clip_box, region_a, region_b, layer_index, l->first, l->second.first, l->second.second, int (nw), int (nh)));
|
||||
job.schedule (new XORTask (deep, tile_desc, clip_box, region_a, region_b, layer_index, l->first, l->second.first, l->second.second, int (nw), int (nh)));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ protected:
|
|||
void run_xor ();
|
||||
|
||||
protected slots:
|
||||
void deep_changed ();
|
||||
void input_changed (int index);
|
||||
void output_changed (int index);
|
||||
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue