diff --git a/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc index ed3856e6e..78c08e706 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc @@ -30,6 +30,8 @@ namespace db { +static const std::pair ext_not_set = std::make_pair (std::numeric_limits::min (), std::numeric_limits::min ()); + struct DEFImporterGroup { DEFImporterGroup (const std::string &n, const std::string &rn, const std::vector &m) @@ -133,7 +135,7 @@ DEFImporter::get_def_ext (const std::string & /*ln*/, const std::pair::const_iterator pt = pts.begin (); + std::vector >::const_iterator ex = ext.begin (); + while (pt != pts.end ()) { - std::vector::const_iterator pt0 = pt; + auto pt0 = pt; + auto ex0 = ex; ++pt; + ++ex; if (pt == pts.end ()) { break; } bool multipart = false; if (is_isotropic) { - while (pt != pts.end () && (pt[-1].x () == pt[0].x () || pt[-1].y () == pt[0].y())) { + while (pt != pts.end ()) { + if (! (pt[-1].x () == pt[0].x () || pt[-1].y () == pt[0].y())) { + // non-orthogonal segments are treated otherwise, not by paths + break; + } + if (pt + 1 != pts.end () && ex[0] != ext_not_set) { + // connection points feature non-default extensions and should not be represented by paths + break; + } ++pt; + ++ex; multipart = true; } if (multipart) { --pt; + --ex; } } - // The next part is the interval [pt0..pt] (pt inclusive) + // The next part is the interval [pt0..pt] (including pt) - if (multipart || (pt0->x () == pt0[1].x () || pt0->y () == pt0[1].y())) { + if (! multipart && (pt0->x () == pt0[1].x () && pt0->y () == pt0[1].y())) { + + // ignore single-point paths + + } else if (multipart || (pt0->x () == pt0[1].x () || pt0->y () == pt0[1].y())) { db::Coord wxy, wxy_perp; @@ -388,33 +408,27 @@ DEFImporter::produce_routing_geometry (db::Cell &design, const Polygon *style, u wxy_perp = w.second; } - // compute begin extension + // compute begin and end extensions db::Coord be = 0; - if (pt0 == pts.begin ()) { - if (pt0->x () == pt0 [1].x ()) { - be = ext.front ().second; - } else { - be = ext.front ().first; - } + if (*ex0 != ext_not_set) { + be = (pt0->x () == pt0 [1].x ()) ? ex0->second : ex0->first; } else if (was_path_before) { // provides the overlap to the previous segment be = wxy_perp / 2; } - // compute end extension db::Coord ee = 0; - if (pt + 1 == pts.end ()) { - if (pt [-1].x () == pt->x ()) { - ee = ext.back ().second; - } else { - ee = ext.back ().first; - } + if (*ex != ext_not_set) { + ee = (pt [-1].x () == pt->x ()) ? ex->second : ex->first; } auto pt_from = pt0; auto pt_to = pt + 1; - // do not split away end segments if they are shorter than half the width + // Pplit paths if "joined_paths" is off. Sorry for spending the effort before to + // compute multipath chains. + // But now we can keep end segments joined if they are shorter than half the width + // to establish a proper path end in that case. auto pt_from_split = pt_from; auto pt_to_split = pt_to; @@ -553,10 +567,6 @@ DEFImporter::read_single_net (std::string &nondefaultrule, Layout &layout, db::C const std::string *rulename = 0; std::pair w (0, 0); - if (specialnets) { - db::Coord n = db::coord_traits::rounded (get_double () * scale); - w = std::make_pair (n, n); - } const db::Polygon *style = 0; @@ -564,6 +574,9 @@ DEFImporter::read_single_net (std::string &nondefaultrule, Layout &layout, db::C if (specialnets) { + db::Coord n = db::coord_traits::rounded (get_double () * scale); + w = std::make_pair (n, n); + while (test ("+")) { if (test ("STYLE")) { @@ -598,11 +611,17 @@ DEFImporter::read_single_net (std::string &nondefaultrule, Layout &layout, db::C rulename = &nondefaultrule; } + if (! specialnets) { + w = get_wire_width_for_rule (*rulename, ln, layout.dbu ()); + } + + // default extension for first and last point std::pair def_ext (0, 0); + std::pair def_ext_conn = get_def_ext (ln, w, layout.dbu ()); if (! specialnets) { - w = get_wire_width_for_rule (*rulename, ln, layout.dbu ()); - def_ext = get_def_ext (ln, w, layout.dbu ()); + // first and last extensions are half width by default for routed nets + def_ext = def_ext_conn; } std::map::const_iterator s = m_styles.find (sn); @@ -694,7 +713,7 @@ DEFImporter::read_single_net (std::string &nondefaultrule, Layout &layout, db::C y = get_double (); } pts.push_back (db::Point (db::DPoint (x * scale, y * scale))); - std::pair ee = def_ext; + std::pair ee = ext_not_set; if (! peek (")")) { db::Coord e = db::coord_traits::rounded (get_double () * scale); ee.first = ee.second = e; @@ -706,10 +725,20 @@ DEFImporter::read_single_net (std::string &nondefaultrule, Layout &layout, db::C } if (pts.size () > 1) { + + // replace the default extensions + if (ext.front () == ext_not_set) { + ext.front () = def_ext; + } + if (ext.back () == ext_not_set) { + ext.back () = def_ext; + } + std::set dl = open_layer (layout, ln, specialnets ? SpecialRouting : Routing, mask); for (std::set::const_iterator l = dl.begin (); l != dl.end (); ++l) { produce_routing_geometry (design, style, *l, prop_id, pts, ext, w); } + } // continue a segment with the current point and the new mask diff --git a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc index 8f27111a6..32898adcf 100644 --- a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc +++ b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc @@ -432,7 +432,7 @@ TEST(def16) // (complete example) db::LEFDEFReaderOptions opt = default_options (); opt.set_macro_resolution_mode (1); - run_test (_this, "def16", "lef:a.lef+lef:tech.lef+def:a.def", "au_4b.oas.gz", opt); + run_test (_this, "def16", "lef:a.lef+lef:tech.lef+def:a.def", "au_4c.oas.gz", opt); } TEST(100) @@ -1153,3 +1153,10 @@ TEST(215_multiDEF) db::compare_layouts (_this, ly, fn_path + "au.oas", db::WriteOAS); } + +// issue-2075 +TEST(216_line_extensions) +{ + run_test (_this, "issue-2075", "map:test.map+lef:test.lef+def:test.def", "au.oas", default_options (), false); +} + diff --git a/testdata/lefdef/issue-2075/au.oas b/testdata/lefdef/issue-2075/au.oas new file mode 100644 index 000000000..08bcd3660 Binary files /dev/null and b/testdata/lefdef/issue-2075/au.oas differ diff --git a/testdata/lefdef/issue-2075/test.def b/testdata/lefdef/issue-2075/test.def new file mode 100644 index 000000000..c25e27049 --- /dev/null +++ b/testdata/lefdef/issue-2075/test.def @@ -0,0 +1,16 @@ +VERSION 5.8 ; + +DESIGN test ; + +UNITS DISTANCE MICRONS 2000 ; + +DIEAREA ( 0 0 ) ( 6000 3000 ) ; + +VIAS 1 ; +END VIAS + +NETS 1 ; + - dummy + ROUTED M2 ( 1670 830 ) ( * * 300 ) ( 4950 * 300 ) ( * 2000 300 ) ; +END NETS + +END DESIGN diff --git a/testdata/lefdef/issue-2075/test.lef b/testdata/lefdef/issue-2075/test.lef new file mode 100644 index 000000000..5892d8ee9 --- /dev/null +++ b/testdata/lefdef/issue-2075/test.lef @@ -0,0 +1,12 @@ +VERSION 5.8 ; + +UNITS + DATABASE MICRONS 2000 ; +END UNITS + +LAYER M2 + TYPE ROUTING ; + WIDTH 0.2 ; +END M2 + +END LIBRARY diff --git a/testdata/lefdef/issue-2075/test.map b/testdata/lefdef/issue-2075/test.map new file mode 100644 index 000000000..c3954ceee --- /dev/null +++ b/testdata/lefdef/issue-2075/test.map @@ -0,0 +1,2 @@ +DIEAREA ALL 108 0 +M2 NET 32 0