mirror of https://github.com/KLayout/klayout.git
The solution is to separate the meaning of "," and "+" layout
file combination operators in strm2x tools:
* "+" does "blending"
* "," does merge
"+" has priority over "," ('a+b,c' acts as '(a+b),c').
NOTE: LEF caching only happens across "+".
This commit is contained in:
parent
0ba6064507
commit
d382629e8e
|
|
@ -43,8 +43,13 @@ int converter_main (int argc, char *argv[], const std::string &format)
|
||||||
generic_reader_options.add_options (cmd);
|
generic_reader_options.add_options (cmd);
|
||||||
|
|
||||||
cmd << tl::arg ("input", &infile, "The input file (any format, may be gzip compressed)",
|
cmd << tl::arg ("input", &infile, "The input file (any format, may be gzip compressed)",
|
||||||
"You can use '+' or ',' to supply multiple files which will be read after each other into the same layout. "
|
"Multiple files can be combined using '+' or ','. '+' will combine the files in 'blending' mode. "
|
||||||
"This provides some cheap, but risky way of merging files. Beware of cell name conflicts.")
|
"In this mode it is possible to combine identically named cells into one cell for example. This mode "
|
||||||
|
"needs to be used with care and there some constraints - e.g. the database unit of the involved "
|
||||||
|
"layouts needs to be the same. When using ',' as a separator, blending is not used, but the layouts "
|
||||||
|
"are merged by first creating two layouts and then combining them into one. This mode is more robust "
|
||||||
|
"but does not allow cell merging. '+' combination has higher priority than ',' - i.e. 'a+b,c' is "
|
||||||
|
"understood as '(a+b),c'.")
|
||||||
<< tl::arg ("output", &outfile, tl::sprintf ("The output file (%s format)", format))
|
<< tl::arg ("output", &outfile, tl::sprintf ("The output file (%s format)", format))
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,8 @@
|
||||||
|
|
||||||
#include "bdReaderOptions.h"
|
#include "bdReaderOptions.h"
|
||||||
#include "dbLoadLayoutOptions.h"
|
#include "dbLoadLayoutOptions.h"
|
||||||
|
#include "dbLayerMapping.h"
|
||||||
|
#include "dbCellMapping.h"
|
||||||
#include "tlCommandLineParser.h"
|
#include "tlCommandLineParser.h"
|
||||||
|
|
||||||
#include "tlStream.h"
|
#include "tlStream.h"
|
||||||
|
|
@ -831,15 +833,28 @@ static std::string::size_type find_file_sep (const std::string &s, std::string::
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<std::string> split_file_list (const std::string &infile)
|
static std::vector<std::vector<std::string> > split_file_list (const std::string &infile)
|
||||||
{
|
{
|
||||||
std::vector<std::string> files;
|
std::vector<std::vector<std::string> > files;
|
||||||
|
files.push_back (std::vector<std::string> ());
|
||||||
|
|
||||||
size_t p = 0;
|
size_t p = 0;
|
||||||
for (size_t pp = 0; (pp = find_file_sep (infile, p)) != std::string::npos; p = pp + 1) {
|
while (true) {
|
||||||
files.push_back (std::string (infile, p, pp - p));
|
|
||||||
|
size_t sep = find_file_sep (infile, p);
|
||||||
|
if (sep == std::string::npos) {
|
||||||
|
files.back ().push_back (std::string (infile, p));
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
files.back ().push_back (std::string (infile, p, sep - p));
|
||||||
|
if (infile [sep] == ',') {
|
||||||
|
files.push_back (std::vector<std::string> ());
|
||||||
|
}
|
||||||
|
|
||||||
|
p = sep + 1;
|
||||||
|
|
||||||
}
|
}
|
||||||
files.push_back (std::string (infile, p));
|
|
||||||
|
|
||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
@ -850,16 +865,47 @@ void read_files (db::Layout &layout, const std::string &infile, const db::LoadLa
|
||||||
// db::LayoutLocker locker (&layout);
|
// db::LayoutLocker locker (&layout);
|
||||||
// but there are yet unknown side effects
|
// but there are yet unknown side effects
|
||||||
|
|
||||||
|
std::vector<std::vector<std::string> > files = split_file_list (infile);
|
||||||
|
|
||||||
|
for (auto ff = files.begin (); ff != files.end (); ++ff) {
|
||||||
|
|
||||||
// enter a LEF caching context for chaining multiple DEF with the same LEF
|
// enter a LEF caching context for chaining multiple DEF with the same LEF
|
||||||
db::LoadLayoutOptions local_options (options);
|
db::LoadLayoutOptions local_options (options);
|
||||||
local_options.set_option_by_name ("lefdef_config.lef_context_enabled", true);
|
local_options.set_option_by_name ("lefdef_config.lef_context_enabled", true);
|
||||||
|
|
||||||
std::vector<std::string> files = split_file_list (infile);
|
db::Layout tmp;
|
||||||
|
db::Layout *ly = (ff == files.begin () ? &layout : &tmp);
|
||||||
|
|
||||||
for (std::vector<std::string>::const_iterator f = files.begin (); f != files.end (); ++f) {
|
for (auto f = ff->begin (); f != ff->end (); ++f) {
|
||||||
tl::InputStream stream (*f);
|
tl::InputStream stream (*f);
|
||||||
db::Reader reader (stream);
|
db::Reader reader (stream);
|
||||||
reader.read (layout, local_options);
|
if (f != ff->begin ()) {
|
||||||
|
reader.set_expected_dbu (ly->dbu ());
|
||||||
|
}
|
||||||
|
reader.read (*ly, local_options);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ly != &layout) {
|
||||||
|
|
||||||
|
// Move over cells from read layout to destination ("," separated blocks).
|
||||||
|
// This path does not imply limitations in terms of DBU compatibility etc.
|
||||||
|
|
||||||
|
std::vector<db::cell_index_type> cells_target;
|
||||||
|
std::vector<db::cell_index_type> cells_source;
|
||||||
|
for (auto c = tmp.begin_top_down (); c != tmp.end_top_cells (); ++c) {
|
||||||
|
cells_source.push_back (*c);
|
||||||
|
cells_target.push_back (layout.add_cell (tmp.cell_name (*c)));
|
||||||
|
}
|
||||||
|
|
||||||
|
db::LayerMapping lm;
|
||||||
|
lm.create_full (layout, tmp);
|
||||||
|
db::CellMapping cm;
|
||||||
|
cm.create_multi_mapping_full (layout, cells_target, tmp, cells_source);
|
||||||
|
|
||||||
|
layout.move_tree_shapes (tmp, cm, lm);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -483,7 +483,7 @@ TEST(10)
|
||||||
std::string input;
|
std::string input;
|
||||||
for (size_t i = 0; i < sizeof (def_files) / sizeof (def_files[0]); ++i) {
|
for (size_t i = 0; i < sizeof (def_files) / sizeof (def_files[0]); ++i) {
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
input += ",";
|
input += "+";
|
||||||
}
|
}
|
||||||
input += def_dir + "/" + def_files[i];
|
input += def_dir + "/" + def_files[i];
|
||||||
}
|
}
|
||||||
|
|
@ -510,3 +510,85 @@ TEST(10)
|
||||||
|
|
||||||
db::compare_layouts (this, layout, input_au, db::WriteOAS);
|
db::compare_layouts (this, layout, input_au, db::WriteOAS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Merging with +
|
||||||
|
TEST(11_1)
|
||||||
|
{
|
||||||
|
std::string input_dir = tl::testdata ();
|
||||||
|
input_dir += "/bd";
|
||||||
|
|
||||||
|
std::string input_au = input_dir + "/strm2oas_au_1.oas";
|
||||||
|
std::string input = input_dir + "/strm2oas_1.oas+" + input_dir + "/strm2oas_2.oas";
|
||||||
|
|
||||||
|
std::string output = this->tmp_file ("strm2oas_1.oas");
|
||||||
|
const char *argv[] = { "x",
|
||||||
|
"--blend-mode=0",
|
||||||
|
input.c_str (),
|
||||||
|
output.c_str ()
|
||||||
|
};
|
||||||
|
|
||||||
|
EXPECT_EQ (bd::converter_main (sizeof (argv) / sizeof (argv[0]), (char **) argv, bd::GenericWriterOptions::oasis_format_name), 0);
|
||||||
|
|
||||||
|
db::Layout layout;
|
||||||
|
{
|
||||||
|
tl::InputStream stream (output);
|
||||||
|
db::LoadLayoutOptions options;
|
||||||
|
db::Reader reader (stream);
|
||||||
|
reader.read (layout, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
db::compare_layouts (this, layout, input_au, db::WriteOAS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merging with + not allowed on different DBUs
|
||||||
|
TEST(11_2)
|
||||||
|
{
|
||||||
|
std::string input_dir = tl::testdata ();
|
||||||
|
input_dir += "/bd";
|
||||||
|
|
||||||
|
std::string input_au = input_dir + "/strm2oas_au_1.oas";
|
||||||
|
std::string input = input_dir + "/strm2oas_1.oas+" + input_dir + "/strm2oas_2_10nm.oas";
|
||||||
|
|
||||||
|
std::string output = this->tmp_file ("strm2oas_1.oas");
|
||||||
|
const char *argv[] = { "x",
|
||||||
|
"--blend-mode=0",
|
||||||
|
input.c_str (),
|
||||||
|
output.c_str ()
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
bd::converter_main (sizeof (argv) / sizeof (argv[0]), (char **) argv, bd::GenericWriterOptions::oasis_format_name);
|
||||||
|
EXPECT_EQ (1, 0);
|
||||||
|
} catch (tl::Exception &ex) {
|
||||||
|
EXPECT_EQ (ex.msg (), "Former and present database units are not compatible: 0.001 (former) vs. 0.01 (present)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merging with + not allowed on different DBUs
|
||||||
|
TEST(11_3)
|
||||||
|
{
|
||||||
|
std::string input_dir = tl::testdata ();
|
||||||
|
input_dir += "/bd";
|
||||||
|
|
||||||
|
std::string input_au = input_dir + "/strm2oas_au_3.oas";
|
||||||
|
std::string input = input_dir + "/strm2oas_1.oas," + input_dir + "/strm2oas_2_10nm.oas";
|
||||||
|
|
||||||
|
std::string output = this->tmp_file ("strm2oas_3.oas");
|
||||||
|
const char *argv[] = { "x",
|
||||||
|
"--blend-mode=0",
|
||||||
|
input.c_str (),
|
||||||
|
output.c_str ()
|
||||||
|
};
|
||||||
|
|
||||||
|
EXPECT_EQ (bd::converter_main (sizeof (argv) / sizeof (argv[0]), (char **) argv, bd::GenericWriterOptions::oasis_format_name), 0);
|
||||||
|
|
||||||
|
db::Layout layout;
|
||||||
|
{
|
||||||
|
tl::InputStream stream (output);
|
||||||
|
db::LoadLayoutOptions options;
|
||||||
|
db::Reader reader (stream);
|
||||||
|
reader.read (layout, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
db::compare_layouts (this, layout, input_au, db::WriteOAS);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,6 @@ ReaderBase::init (const db::LoadLayoutOptions &options)
|
||||||
m_last_warning.clear ();
|
m_last_warning.clear ();
|
||||||
m_warn_count_for_same_message = 0;
|
m_warn_count_for_same_message = 0;
|
||||||
m_first_warning = true;
|
m_first_warning = true;
|
||||||
m_expected_dbu = 0.0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
|
||||||
|
|
@ -259,6 +259,22 @@ public:
|
||||||
return mp_actual_reader->warnings_as_errors ();
|
return mp_actual_reader->warnings_as_errors ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the expected database unit (see ReaderBase)
|
||||||
|
*/
|
||||||
|
void set_expected_dbu (double dbu)
|
||||||
|
{
|
||||||
|
return mp_actual_reader->set_expected_dbu (dbu);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the expected database unit
|
||||||
|
*/
|
||||||
|
double expected_dbu () const
|
||||||
|
{
|
||||||
|
return mp_actual_reader->expected_dbu ();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ReaderBase *mp_actual_reader;
|
ReaderBase *mp_actual_reader;
|
||||||
tl::InputStream &m_stream;
|
tl::InputStream &m_stream;
|
||||||
|
|
|
||||||
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