Skip to content

Commit 131f36a

Browse files
Merge pull request #2084 from KLayout/feature/issue-2044
Feature/issue 2044
2 parents 2d3f445 + 1512076 commit 131f36a

29 files changed

+365
-21
lines changed

src/buddies/src/bd/bdConverterMain.cc

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,13 @@ int converter_main (int argc, char *argv[], const std::string &format)
4343
generic_reader_options.add_options (cmd);
4444

4545
cmd << tl::arg ("input", &infile, "The input file (any format, may be gzip compressed)",
46-
"You can use '+' or ',' to supply multiple files which will be read after each other into the same layout. "
47-
"This provides some cheap, but risky way of merging files. Beware of cell name conflicts.")
46+
"Multiple files can be combined using '+' or ','. '+' will combine the files in 'blending' mode. "
47+
"In this mode it is possible to combine identically named cells into one cell for example. This mode "
48+
"needs to be used with care and there some constraints - e.g. the database unit of the involved "
49+
"layouts needs to be the same. When using ',' as a separator, blending is not used, but the layouts "
50+
"are merged by first creating two layouts and then combining them into one. This mode is more robust "
51+
"but does not allow cell merging. '+' combination has higher priority than ',' - i.e. 'a+b,c' is "
52+
"understood as '(a+b),c'.")
4853
<< tl::arg ("output", &outfile, tl::sprintf ("The output file (%s format)", format))
4954
;
5055

src/buddies/src/bd/bdReaderOptions.cc

Lines changed: 85 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222

2323
#include "bdReaderOptions.h"
2424
#include "dbLoadLayoutOptions.h"
25+
#include "dbLayerMapping.h"
26+
#include "dbCellMapping.h"
2527
#include "tlCommandLineParser.h"
2628

2729
#include "tlStream.h"
@@ -831,15 +833,28 @@ static std::string::size_type find_file_sep (const std::string &s, std::string::
831833
}
832834
}
833835

834-
static std::vector<std::string> split_file_list (const std::string &infile)
836+
static std::vector<std::vector<std::string> > split_file_list (const std::string &infile)
835837
{
836-
std::vector<std::string> files;
838+
std::vector<std::vector<std::string> > files;
839+
files.push_back (std::vector<std::string> ());
837840

838841
size_t p = 0;
839-
for (size_t pp = 0; (pp = find_file_sep (infile, p)) != std::string::npos; p = pp + 1) {
840-
files.push_back (std::string (infile, p, pp - p));
842+
while (true) {
843+
844+
size_t sep = find_file_sep (infile, p);
845+
if (sep == std::string::npos) {
846+
files.back ().push_back (std::string (infile, p));
847+
return files;
848+
}
849+
850+
files.back ().push_back (std::string (infile, p, sep - p));
851+
if (infile [sep] == ',') {
852+
files.push_back (std::vector<std::string> ());
853+
}
854+
855+
p = sep + 1;
856+
841857
}
842-
files.push_back (std::string (infile, p));
843858

844859
return files;
845860
}
@@ -850,16 +865,73 @@ void read_files (db::Layout &layout, const std::string &infile, const db::LoadLa
850865
// db::LayoutLocker locker (&layout);
851866
// but there are yet unknown side effects
852867

853-
// enter a LEF caching context for chaining multiple DEF with the same LEF
854-
db::LoadLayoutOptions local_options (options);
855-
local_options.set_option_by_name ("lefdef_config.lef_context_enabled", true);
868+
std::vector<std::vector<std::string> > files = split_file_list (infile);
869+
870+
for (auto ff = files.begin (); ff != files.end (); ++ff) {
871+
872+
// enter a LEF caching context for chaining multiple DEF with the same LEF
873+
db::LoadLayoutOptions local_options (options);
874+
local_options.set_option_by_name ("lefdef_config.lef_context_enabled", true);
875+
876+
db::Layout tmp;
877+
db::Layout *ly = (ff == files.begin () ? &layout : &tmp);
878+
879+
for (auto f = ff->begin (); f != ff->end (); ++f) {
880+
tl::InputStream stream (*f);
881+
db::Reader reader (stream);
882+
if (f != ff->begin ()) {
883+
reader.set_expected_dbu (ly->dbu ());
884+
}
885+
reader.read (*ly, local_options);
886+
}
887+
888+
if (ly != &layout) {
889+
890+
// Move over cells from read layout to destination ("," separated blocks).
891+
// This path does not imply limitations in terms of DBU compatibility etc.
892+
893+
std::vector<db::cell_index_type> cells_target;
894+
std::vector<db::cell_index_type> cells_source;
895+
896+
for (auto c = tmp.begin_top_down (); c != tmp.end_top_cells (); ++c) {
897+
898+
cells_source.push_back (*c);
899+
900+
// as a special rule, join ghost cells if the source top cell fits into
901+
// a ghost cell of the target.
902+
auto cell_target = layout.cell_by_name (tmp.cell_name (*c));
903+
if (cell_target.first && layout.cell (cell_target.second).is_ghost_cell ()) {
904+
cells_target.push_back (cell_target.second);
905+
} else {
906+
cells_target.push_back (layout.add_cell (tmp.cell_name (*c)));
907+
}
908+
909+
}
910+
911+
// ghost cell joining also works the other way around: a top cell of destination
912+
// can match a ghost cell of the source
913+
for (auto c = tmp.end_top_cells (); c != tmp.end_top_down (); ++c) {
914+
915+
const db::Cell &cell_source = tmp.cell (*c);
916+
auto cell_target = layout.cell_by_name (tmp.cell_name (*c));
917+
918+
if (cell_source.is_ghost_cell () && cell_target.first) {
919+
cells_source.push_back (*c);
920+
cells_target.push_back (cell_target.second);
921+
}
922+
923+
}
924+
925+
db::CellMapping cm;
926+
cm.create_multi_mapping_full (layout, cells_target, tmp, cells_source);
927+
928+
db::LayerMapping lm;
929+
lm.create_full (layout, tmp);
930+
931+
layout.move_tree_shapes (tmp, cm, lm);
856932

857-
std::vector<std::string> files = split_file_list (infile);
933+
}
858934

859-
for (std::vector<std::string>::const_iterator f = files.begin (); f != files.end (); ++f) {
860-
tl::InputStream stream (*f);
861-
db::Reader reader (stream);
862-
reader.read (layout, local_options);
863935
}
864936
}
865937

src/buddies/unit_tests/bdConverterTests.cc

Lines changed: 199 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,7 @@ TEST(10)
483483
std::string input;
484484
for (size_t i = 0; i < sizeof (def_files) / sizeof (def_files[0]); ++i) {
485485
if (i > 0) {
486-
input += ",";
486+
input += "+";
487487
}
488488
input += def_dir + "/" + def_files[i];
489489
}
@@ -510,3 +510,201 @@ TEST(10)
510510

511511
db::compare_layouts (this, layout, input_au, db::WriteOAS);
512512
}
513+
514+
// Merging with +
515+
TEST(11_1)
516+
{
517+
std::string input_dir = tl::testdata ();
518+
input_dir += "/bd";
519+
520+
std::string input_au = input_dir + "/strm2oas_au_1.oas";
521+
std::string input = input_dir + "/strm2oas_1.oas+" + input_dir + "/strm2oas_2.oas";
522+
523+
std::string output = this->tmp_file ("strm2oas_1.oas");
524+
const char *argv[] = { "x",
525+
"--blend-mode=0",
526+
input.c_str (),
527+
output.c_str ()
528+
};
529+
530+
EXPECT_EQ (bd::converter_main (sizeof (argv) / sizeof (argv[0]), (char **) argv, bd::GenericWriterOptions::oasis_format_name), 0);
531+
532+
db::Layout layout;
533+
{
534+
tl::InputStream stream (output);
535+
db::LoadLayoutOptions options;
536+
db::Reader reader (stream);
537+
reader.read (layout, options);
538+
}
539+
540+
db::compare_layouts (this, layout, input_au, db::WriteOAS);
541+
}
542+
543+
// Merging with + not allowed on different DBUs
544+
TEST(11_2)
545+
{
546+
std::string input_dir = tl::testdata ();
547+
input_dir += "/bd";
548+
549+
std::string input_au = input_dir + "/strm2oas_au_1.oas";
550+
std::string input = input_dir + "/strm2oas_1.oas+" + input_dir + "/strm2oas_2_10nm.oas";
551+
552+
std::string output = this->tmp_file ("strm2oas_1.oas");
553+
const char *argv[] = { "x",
554+
"--blend-mode=0",
555+
input.c_str (),
556+
output.c_str ()
557+
};
558+
559+
try {
560+
bd::converter_main (sizeof (argv) / sizeof (argv[0]), (char **) argv, bd::GenericWriterOptions::oasis_format_name);
561+
EXPECT_EQ (1, 0);
562+
} catch (tl::Exception &ex) {
563+
EXPECT_EQ (ex.msg (), "Former and present database units are not compatible: 0.001 (former) vs. 0.01 (present)");
564+
}
565+
}
566+
567+
// Merging with + not allowed on different DBUs
568+
TEST(11_3)
569+
{
570+
std::string input_dir = tl::testdata ();
571+
input_dir += "/bd";
572+
573+
std::string input_au = input_dir + "/strm2oas_au_3.oas";
574+
std::string input = input_dir + "/strm2oas_1.oas," + input_dir + "/strm2oas_2_10nm.oas";
575+
576+
std::string output = this->tmp_file ("strm2oas_3.oas");
577+
const char *argv[] = { "x",
578+
"--blend-mode=0",
579+
input.c_str (),
580+
output.c_str ()
581+
};
582+
583+
EXPECT_EQ (bd::converter_main (sizeof (argv) / sizeof (argv[0]), (char **) argv, bd::GenericWriterOptions::oasis_format_name), 0);
584+
585+
db::Layout layout;
586+
{
587+
tl::InputStream stream (output);
588+
db::LoadLayoutOptions options;
589+
db::Reader reader (stream);
590+
reader.read (layout, options);
591+
}
592+
593+
db::compare_layouts (this, layout, input_au, db::WriteOAS);
594+
}
595+
596+
// Merging with + and , under the presence of ghost cells: test+test,top->(test)
597+
TEST(12_1)
598+
{
599+
std::string input_dir = tl::testdata ();
600+
input_dir += "/bd";
601+
602+
std::string input_au = input_dir + "/strm2oas_au_12_1.oas";
603+
std::string input = input_dir + "/strm2oas_a.oas+" + input_dir + "/strm2oas_b.oas," + input_dir + "/strm2oas_c.oas";
604+
605+
std::string output = this->tmp_file ("strm2oas_12_1.oas");
606+
const char *argv[] = { "x",
607+
"--blend-mode=0",
608+
input.c_str (),
609+
output.c_str ()
610+
};
611+
612+
EXPECT_EQ (bd::converter_main (sizeof (argv) / sizeof (argv[0]), (char **) argv, bd::GenericWriterOptions::oasis_format_name), 0);
613+
614+
db::Layout layout;
615+
{
616+
tl::InputStream stream (output);
617+
db::LoadLayoutOptions options;
618+
db::Reader reader (stream);
619+
reader.read (layout, options);
620+
}
621+
622+
db::compare_layouts (this, layout, input_au, db::WriteOAS);
623+
}
624+
625+
// Merging with + and , under the presence of ghost cells: top->(test),test+test
626+
TEST(12_2)
627+
{
628+
std::string input_dir = tl::testdata ();
629+
input_dir += "/bd";
630+
631+
std::string input_au = input_dir + "/strm2oas_au_12_2.oas";
632+
std::string input = input_dir + "/strm2oas_c.oas," + input_dir + "/strm2oas_a.oas+" + input_dir + "/strm2oas_b.oas";
633+
634+
std::string output = this->tmp_file ("strm2oas_12_2.oas");
635+
const char *argv[] = { "x",
636+
"--blend-mode=0",
637+
input.c_str (),
638+
output.c_str ()
639+
};
640+
641+
EXPECT_EQ (bd::converter_main (sizeof (argv) / sizeof (argv[0]), (char **) argv, bd::GenericWriterOptions::oasis_format_name), 0);
642+
643+
db::Layout layout;
644+
{
645+
tl::InputStream stream (output);
646+
db::LoadLayoutOptions options;
647+
db::Reader reader (stream);
648+
reader.read (layout, options);
649+
}
650+
651+
db::compare_layouts (this, layout, input_au, db::WriteOAS);
652+
}
653+
654+
// Merging with + and , under the presence of ghost cells: test+test,toptop->top->(test)
655+
TEST(12_3)
656+
{
657+
std::string input_dir = tl::testdata ();
658+
input_dir += "/bd";
659+
660+
std::string input_au = input_dir + "/strm2oas_au_12_3.oas";
661+
std::string input = input_dir + "/strm2oas_a.oas+" + input_dir + "/strm2oas_b.oas," + input_dir + "/strm2oas_cc.oas";
662+
663+
std::string output = this->tmp_file ("strm2oas_12_3.oas");
664+
const char *argv[] = { "x",
665+
"--blend-mode=0",
666+
input.c_str (),
667+
output.c_str ()
668+
};
669+
670+
EXPECT_EQ (bd::converter_main (sizeof (argv) / sizeof (argv[0]), (char **) argv, bd::GenericWriterOptions::oasis_format_name), 0);
671+
672+
db::Layout layout;
673+
{
674+
tl::InputStream stream (output);
675+
db::LoadLayoutOptions options;
676+
db::Reader reader (stream);
677+
reader.read (layout, options);
678+
}
679+
680+
db::compare_layouts (this, layout, input_au, db::WriteOAS);
681+
}
682+
683+
// Merging with + and , under the presence of ghost cells: toptop->top->(test),test+test
684+
TEST(12_4)
685+
{
686+
std::string input_dir = tl::testdata ();
687+
input_dir += "/bd";
688+
689+
std::string input_au = input_dir + "/strm2oas_au_12_4.oas";
690+
std::string input = input_dir + "/strm2oas_cc.oas," + input_dir + "/strm2oas_a.oas+" + input_dir + "/strm2oas_b.oas";
691+
692+
std::string output = this->tmp_file ("strm2oas_12_4.oas");
693+
const char *argv[] = { "x",
694+
"--blend-mode=0",
695+
input.c_str (),
696+
output.c_str ()
697+
};
698+
699+
EXPECT_EQ (bd::converter_main (sizeof (argv) / sizeof (argv[0]), (char **) argv, bd::GenericWriterOptions::oasis_format_name), 0);
700+
701+
db::Layout layout;
702+
{
703+
tl::InputStream stream (output);
704+
db::LoadLayoutOptions options;
705+
db::Reader reader (stream);
706+
reader.read (layout, options);
707+
}
708+
709+
db::compare_layouts (this, layout, input_au, db::WriteOAS);
710+
}

src/db/db/dbReader.cc

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ join_layer_names (std::string &s, const std::string &n)
6161
// ReaderBase implementation
6262

6363
ReaderBase::ReaderBase ()
64-
: m_warnings_as_errors (false), m_warn_level (1), m_warn_count_for_same_message (0), m_first_warning (true)
64+
: m_warnings_as_errors (false), m_warn_level (1), m_warn_count_for_same_message (0), m_first_warning (true), m_expected_dbu (0.0)
6565
{
6666
}
6767

@@ -114,6 +114,20 @@ ReaderBase::compress_warning (const std::string &msg)
114114
}
115115
}
116116

117+
void
118+
ReaderBase::set_expected_dbu (double dbu)
119+
{
120+
m_expected_dbu = dbu;
121+
}
122+
123+
void
124+
ReaderBase::check_dbu (double dbu) const
125+
{
126+
if (m_expected_dbu > db::epsilon && fabs (dbu - m_expected_dbu) > db::epsilon) {
127+
throw ReaderException (tl::sprintf (tl::to_string (tr ("Former and present database units are not compatible: %.12g (former) vs. %.12g (present)")), m_expected_dbu, dbu));
128+
}
129+
}
130+
117131
// ---------------------------------------------------------------
118132
// Reader implementation
119133

0 commit comments

Comments
 (0)