From f11a3a0dd5e1f2a34a0b2ffdced8b95ebc924704 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 4 Apr 2020 18:48:25 +0200 Subject: [PATCH] Bugfix: MINWIDTH ... WRONGDIRECTION wasn't considering DIRECTION VERTICAL Added/updated some tests, some refactoring. --- .../lefdef/db_plugin/dbDEFImporter.cc | 165 +++++++++--------- .../lefdef/db_plugin/dbDEFImporter.h | 4 +- .../lefdef/db_plugin/dbLEFImporter.cc | 68 ++++++-- .../lefdef/db_plugin/dbLEFImporter.h | 6 +- .../lefdef/unit_tests/dbLEFDEFImportTests.cc | 11 ++ testdata/lefdef/scanchain/au.oas.gz | Bin 0 -> 153 bytes testdata/lefdef/scanchain/test.def | 32 ++++ testdata/lefdef/specialwidths/au.oas.gz | Bin 0 -> 316 bytes testdata/lefdef/specialwidths/test.def | 19 ++ testdata/lefdef/specialwidths/test.lef | 43 +++++ 10 files changed, 245 insertions(+), 103 deletions(-) create mode 100644 testdata/lefdef/scanchain/au.oas.gz create mode 100644 testdata/lefdef/scanchain/test.def create mode 100644 testdata/lefdef/specialwidths/au.oas.gz create mode 100644 testdata/lefdef/specialwidths/test.def create mode 100644 testdata/lefdef/specialwidths/test.lef diff --git a/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc index fb1953cda..cdbaf91e9 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc @@ -139,15 +139,17 @@ struct Group std::pair DEFImporter::get_wire_width_for_rule (const std::string &rulename, const std::string &ln, double dbu) { - db::Coord w = db::coord_traits::rounded (m_lef_importer.layer_width (ln, rulename, 0.0) / dbu); + std::pair wxy = m_lef_importer.layer_width (ln, rulename); + db::Coord wx = db::coord_traits::rounded (wxy.first / dbu); + db::Coord wy = db::coord_traits::rounded (wxy.second / dbu); // try to find local nondefault rule if (! rulename.empty ()) { - std::map >::const_iterator nd = m_nondefault_widths.find (rulename); + std::map >::const_iterator nd = m_nondefault_widths.find (rulename); if (nd != m_nondefault_widths.end ()) { - std::map::const_iterator ld = nd->second.find (ln); + std::map::const_iterator ld = nd->second.find (ln); if (ld != nd->second.end ()) { - w = ld->second; + wx = wy = ld->second; } } } @@ -156,30 +158,87 @@ DEFImporter::get_wire_width_for_rule (const std::string &rulename, const std::st db::Coord min_wx = db::coord_traits::rounded (min_wxy.first / dbu); db::Coord min_wy = db::coord_traits::rounded (min_wxy.second / dbu); - return std::make_pair (std::max (w, min_wx), std::max (w, min_wy)); + return std::make_pair (std::max (wx, min_wx), std::max (wy, min_wy)); } std::pair DEFImporter::get_def_ext (const std::string &ln, const std::pair &wxy, double dbu) { - if (wxy.first == wxy.second) { - db::Coord de = db::coord_traits::rounded (m_lef_importer.layer_ext (ln, wxy.first * 0.5 * dbu) / dbu); - return std::make_pair (de, de); - } else { -#if 0 - // This implementation picks the default extension according to the real width - // NOTE: the swapping of x and y for the default extension is intended. For horizontal lines, the - // extension is in x direction but corresponds to a wire width of a vertical wire and vice versa. - db::Coord dex = db::coord_traits::rounded (m_lef_importer.layer_ext (ln, wxy.second * 0.5 * dbu) / dbu); - db::Coord dey = db::coord_traits::rounded (m_lef_importer.layer_ext (ln, wxy.first * 0.5 * dbu) / dbu); - return std::make_pair (dex, dey); -#else - // This implementation picks the default extension according to the specified wire width (which is the minimum - // of wx and wy) - db::Coord de = db::coord_traits::rounded (m_lef_importer.layer_ext (ln, std::min (wxy.first, wxy.second) * 0.5 * dbu) / dbu); - return std::make_pair (de, de); -#endif + // This implementation assumes the "preferred width" is controlling the default extension and it is + // identical to the minimum effective width. This is true if "LEF58_MINWIDTH" with "WRONGDIRECTION" is + // used in the proposed way. Which is to specify a larger width for the "wrong" direction. + db::Coord de = db::coord_traits::rounded (m_lef_importer.layer_ext (ln, std::min (wxy.first, wxy.second) * 0.5 * dbu) / dbu); + return std::make_pair (de, de); +} + +void +DEFImporter::read_diearea (db::Layout &layout, db::Cell &design, double scale) +{ + std::vector points; + + while (! test (";")) { + test ("("); + double x = get_double (); + double y = get_double (); + points.push_back (db::DPoint (x * scale, y * scale)); + test (")"); } + + if (points.size () >= 2) { + + // create outline shape + std::pair dl = open_layer (layout, std::string (), Outline); + if (dl.first) { + if (points.size () == 2) { + design.shapes (dl.second).insert (db::Box (db::DBox (points [0], points [1]))); + } else { + db::DPolygon p; + p.assign_hull (points.begin (), points.end ()); + design.shapes (dl.second).insert (db::Polygon (p)); + } + } + + } +} + +void +DEFImporter::read_nondefaultrules (double scale) +{ + // read NONDEFAULTRULES sections + get_long (); + expect (";"); + + while (test ("-")) { + + std::string n = get (); + + while (test ("+")) { + + if (test ("LAYER")) { + + std::string l = get (); + + // read the width for the layer + if (test ("WIDTH")) { + double w = get_double () * scale; + m_nondefault_widths[n][l] = db::coord_traits::rounded (w); + } + + } + + // parse over the rest + while (! peek ("+") && ! peek ("-") && ! peek (";")) { + take (); + } + + } + + test (";"); + + } + + test ("END"); + test ("NONDEFAULTRULES"); } void @@ -231,31 +290,7 @@ DEFImporter::do_read (db::Layout &layout) } else if (test ("DIEAREA")) { - std::vector points; - - while (! test (";")) { - test ("("); - double x = get_double (); - double y = get_double (); - points.push_back (db::DPoint (x * scale, y * scale)); - test (")"); - } - - if (points.size () >= 2) { - - // create outline shape - std::pair dl = open_layer (layout, std::string (), Outline); - if (dl.first) { - if (points.size () == 2) { - design.shapes (dl.second).insert (db::Box (db::DBox (points [0], points [1]))); - } else { - db::DPolygon p; - p.assign_hull (points.begin (), points.end ()); - design.shapes (dl.second).insert (db::Polygon (p)); - } - } - - } + read_diearea (layout, design, scale); } else if (test ("PROPERTYDEFINITIONS")) { // read over PROPERTYDEFINITIONS sections @@ -265,41 +300,7 @@ DEFImporter::do_read (db::Layout &layout) } else if (test ("NONDEFAULTRULES")) { - // read NONDEFAULTRULES sections - get_long (); - expect (";"); - - while (test ("-")) { - - std::string n = get (); - - while (test ("+")) { - - if (test ("LAYER")) { - - std::string l = get (); - - // read the width for the layer - if (test ("WIDTH")) { - double w = get_double () * scale; - m_nondefault_widths[n][l] = w; - } - - } - - // parse over the rest - while (! peek ("+") && ! peek ("-") && ! peek (";")) { - take (); - } - - } - - test (";"); - - } - - test ("END"); - test ("NONDEFAULTRULES"); + read_nondefaultrules (scale); } else if (test ("REGIONS")) { diff --git a/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.h b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.h index fa4a377a4..4fa08fbc3 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.h +++ b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.h @@ -61,13 +61,15 @@ protected: private: LEFImporter m_lef_importer; - std::map > m_nondefault_widths; + std::map > m_nondefault_widths; db::FTrans get_orient (bool optional); void read_polygon (db::Polygon &poly, double scale); void read_rect (db::Polygon &poly, double scale); std::pair get_wire_width_for_rule(const std::string &rule, const std::string &ln, double dbu); std::pair get_def_ext (const std::string &ln, const std::pair &wxy, double dbu); + void read_diearea (db::Layout &layout, db::Cell &design, double scale); + void read_nondefaultrules (double scale); }; } diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc index f43d905fb..cb5995b1d 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc @@ -76,12 +76,12 @@ LEFImporter::min_layer_width (const std::string &layer) const } } -double -LEFImporter::layer_width (const std::string &layer, const std::string &nondefaultrule, double def_width) const +std::pair +LEFImporter::layer_width (const std::string &layer, const std::string &nondefaultrule, const std::pair &def_width) const { - std::map >::const_iterator nd = m_nondefault_widths.find (nondefaultrule); + std::map > >::const_iterator nd = m_nondefault_widths.find (nondefaultrule); - std::map::const_iterator l; + std::map >::const_iterator l; bool has_width = false; if (! nondefaultrule.empty () && nd != m_nondefault_widths.end ()) { @@ -185,9 +185,9 @@ LEFImporter::read_geometries (db::Layout &layout, db::Cell &cell, LayerPurpose p } w = 0.0; - std::map::const_iterator dw = m_default_widths.find (layer_name); + std::map >::const_iterator dw = m_default_widths.find (layer_name); if (dw != m_default_widths.end ()) { - w = dw->second; + w = dw->second.first; } while (! test (";")) { @@ -388,7 +388,7 @@ LEFImporter::read_nondefaultrule (db::Layout & /*layout*/) if (test ("WIDTH")) { double w = get_double (); test (";"); - m_nondefault_widths[n][l] = w; + m_nondefault_widths[n][l] = std::make_pair (w, w); } else { while (! test (";")) { take (); @@ -590,7 +590,8 @@ LEFImporter::read_layer (Layout & /*layout*/) { std::string ln = get (); double wmin = 0.0, wmin_wrongdir = 0.0; - bool is_horizontal = true; + double w = 0.0, w_wrongdir = 0.0; + bool is_horizontal = false; register_layer (ln); @@ -615,8 +616,12 @@ LEFImporter::read_layer (Layout & /*layout*/) } else if (test ("WIDTH")) { - double w = get_double (); - m_default_widths.insert (std::make_pair (ln, w)); + w = get_double (); + expect (";"); + + } else if (test ("MINWIDTH")) { + + wmin = get_double (); expect (";"); } else if (test ("DIRECTION")) { @@ -629,8 +634,8 @@ LEFImporter::read_layer (Layout & /*layout*/) } else if (test ("WIREEXTENSION")) { - double w = get_double (); - m_default_ext.insert (std::make_pair (ln, w)); + double v = get_double (); + m_default_ext.insert (std::make_pair (ln, v)); expect (";"); } else if (test ("ACCURRENTDENSITY")) { @@ -656,17 +661,32 @@ LEFImporter::read_layer (Layout & /*layout*/) // Cadence extension tl::Extractor ex (value.to_string ()); - double mw = 0.0; - if (ex.test ("MINWIDTH") && ex.try_read (mw)) { + double v = 0.0; + if (ex.test ("MINWIDTH") && ex.try_read (v)) { if (ex.test ("WRONGDIRECTION")) { - wmin_wrongdir = mw; + wmin_wrongdir = v; } else { - wmin = mw; + wmin = v; + } + } + + } else if (name == "LEF58_WIDTH") { + + // Cadence extension + tl::Extractor ex (value.to_string ()); + double v = 0.0; + if (ex.test ("WIDTH") && ex.try_read (v)) { + if (ex.test ("WRONGDIRECTION")) { + w_wrongdir = v; + } else { + w = v; } } } + expect (";"); + } else { while (! test (";")) { @@ -676,9 +696,23 @@ LEFImporter::read_layer (Layout & /*layout*/) } } + if (w > 0.0 || w_wrongdir > 0.0) { + + if (w_wrongdir == 0.0) { + w_wrongdir = w; + } else if (! is_horizontal) { + std::swap (w, w_wrongdir); + } + + m_default_widths.insert (std::make_pair (ln, std::make_pair (w, w_wrongdir))); + + } + if (wmin > 0.0 || wmin_wrongdir > 0.0) { - if (! is_horizontal) { + if (wmin_wrongdir == 0.0) { + wmin_wrongdir = wmin; + } else if (! is_horizontal) { std::swap (wmin, wmin_wrongdir); } diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.h b/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.h index 7bc672639..f52133996 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.h +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.h @@ -77,7 +77,7 @@ public: * The nondefaultrule name gives the name of the nondefaultrule or an empty string if * none is requested. */ - double layer_width (const std::string &layer, const std::string &nondefaultrule, double def_width = 0.0) const; + std::pair layer_width (const std::string &layer, const std::string &nondefaultrule, const std::pair &def_width = std::make_pair (0.0, 0.0)) const; /** * @brief Get the extension for a layer with the given name @@ -121,8 +121,8 @@ protected: void do_read (db::Layout &layout); private: - std::map > m_nondefault_widths; - std::map m_default_widths; + std::map > > m_nondefault_widths; + std::map > m_default_widths; std::map m_default_ext; std::map > m_min_widths; std::map m_macros_by_name; diff --git a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc index 249bf79ed..fd9b1b896 100644 --- a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc +++ b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc @@ -284,3 +284,14 @@ TEST(106_wrongdirection) { run_test (_this, "wrongdirection", "lef:test.lef+def:test.def", "au.oas.gz", default_options (), false); } + +TEST(107_specialwidths) +{ + run_test (_this, "specialwidths", "lef:test.lef+def:test.def", "au.oas.gz", default_options (), false); +} + +TEST(108_scanchain) +{ + run_test (_this, "scanchain", "def:test.def", "au.oas.gz", default_options (), false); +} + diff --git a/testdata/lefdef/scanchain/au.oas.gz b/testdata/lefdef/scanchain/au.oas.gz new file mode 100644 index 0000000000000000000000000000000000000000..62bd9872536a29580951b0170ce152a8118aac84 GIT binary patch literal 153 zcmV;K0A~LmiwFqBxQJc=17US8Z((x)Qw?_Y_0;uu4E7A>JUCcncx52cp?=sD$cSJUCcncx52cp?=sD$cS4!psa-1E#sz{X;{1JpEjmS%8Ab99{;IYDR_yY&TdIvfX46sbspr z@`d>(%U5QRO6CjvFW4{gzhviS6nwz2Kwj)IBf|t{{x8g5m>C!s$jhiRa4_;Sh`sp5 z2m}k|7s$(seFVz!-(b1H!U$Awz)n_d29Rcu6??IUi3b>dKn_rq$W4|Behdsu4I>#a OFaQ7#X*JMe0ssK6;Epo@ literal 0 HcmV?d00001 diff --git a/testdata/lefdef/specialwidths/test.def b/testdata/lefdef/specialwidths/test.def new file mode 100644 index 000000000..9f53fde84 --- /dev/null +++ b/testdata/lefdef/specialwidths/test.def @@ -0,0 +1,19 @@ +VERSION 5.8 ; +DIVIDERCHAR "/" ; +BUSBITCHARS "[]" ; +DESIGN test ; +UNITS DISTANCE MICRONS 1000 ; +DIEAREA ( 0 0 ) ( 10000 10000 ) ; +NONDEFAULTRULES 1 ; + - ndr + + HARDSPACING + + LAYER M3 WIDTH 500 SPACING 500 +; +END NONDEFAULTRULES +NETS 1 ; + - net_b + + NONDEFAULTRULE ndr + + ROUTED M3 ( 0 2000 ) ( 0 0 ) ( 2000 0 ) via34 ( * 2000 ) ( 4000 * ) ( * 4000 ) + ; +END NETS +END DESIGN diff --git a/testdata/lefdef/specialwidths/test.lef b/testdata/lefdef/specialwidths/test.lef new file mode 100644 index 000000000..2d0b5edc9 --- /dev/null +++ b/testdata/lefdef/specialwidths/test.lef @@ -0,0 +1,43 @@ +VERSION 5.8 ; +BUSBITCHARS "[]" ; +DIVIDERCHAR "/" ; + +UNITS + DATABASE MICRONS 1000 ; +END UNITS + +MANUFACTURINGGRID 0.001 ; + +PROPERTYDEFINITIONS + LAYER LEF58_MINWIDTH STRING ; +END PROPERTYDEFINITIONS + +LAYER M3 + TYPE ROUTING ; + DIRECTION VERTICAL ; + WIDTH 0.4 ; + PROPERTY LEF58_MINWIDTH "MINWIDTH 0.5 ; " ; + PROPERTY LEF58_MINWIDTH "MINWIDTH 0.8 WRONGDIRECTION ; " ; +END M3 + +LAYER VIA3 + TYPE CUT ; +END VIA3 + +LAYER M4 + TYPE ROUTING ; + DIRECTION HORIZONTAL ; + PROPERTY LEF58_WIDTH "WIDTH 0.6 ; " ; + PROPERTY LEF58_WIDTH "WIDTH 1.0 WRONGDIRECTION ; " ; +END M4 + +VIA via34 + LAYER M3 ; + RECT -0.4 -0.3 0.4 0.3 ; + LAYER VIA3 ; + RECT -0.3 -0.25 0.3 0.25 ; + LAYER M4 ; + RECT -1.00 -0.5 1.00 0.5 ; +END via34 + +END LIBRARY