Bugfix: MINWIDTH ... WRONGDIRECTION wasn't considering DIRECTION VERTICAL

Added/updated some tests, some refactoring.
This commit is contained in:
Matthias Koefferlein 2020-04-04 18:48:25 +02:00
parent 4a24b727d5
commit f11a3a0dd5
10 changed files with 245 additions and 103 deletions

View File

@ -139,15 +139,17 @@ struct Group
std::pair<db::Coord, db::Coord> std::pair<db::Coord, db::Coord>
DEFImporter::get_wire_width_for_rule (const std::string &rulename, const std::string &ln, double dbu) DEFImporter::get_wire_width_for_rule (const std::string &rulename, const std::string &ln, double dbu)
{ {
db::Coord w = db::coord_traits<db::Coord>::rounded (m_lef_importer.layer_width (ln, rulename, 0.0) / dbu); std::pair<double, double> wxy = m_lef_importer.layer_width (ln, rulename);
db::Coord wx = db::coord_traits<db::Coord>::rounded (wxy.first / dbu);
db::Coord wy = db::coord_traits<db::Coord>::rounded (wxy.second / dbu);
// try to find local nondefault rule // try to find local nondefault rule
if (! rulename.empty ()) { if (! rulename.empty ()) {
std::map<std::string, std::map<std::string, double> >::const_iterator nd = m_nondefault_widths.find (rulename); std::map<std::string, std::map<std::string, db::Coord> >::const_iterator nd = m_nondefault_widths.find (rulename);
if (nd != m_nondefault_widths.end ()) { if (nd != m_nondefault_widths.end ()) {
std::map<std::string, double>::const_iterator ld = nd->second.find (ln); std::map<std::string, db::Coord>::const_iterator ld = nd->second.find (ln);
if (ld != nd->second.end ()) { 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<db::Coord>::rounded (min_wxy.first / dbu); db::Coord min_wx = db::coord_traits<db::Coord>::rounded (min_wxy.first / dbu);
db::Coord min_wy = db::coord_traits<db::Coord>::rounded (min_wxy.second / dbu); db::Coord min_wy = db::coord_traits<db::Coord>::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<db::Coord, db::Coord> std::pair<db::Coord, db::Coord>
DEFImporter::get_def_ext (const std::string &ln, const std::pair<db::Coord, db::Coord> &wxy, double dbu) DEFImporter::get_def_ext (const std::string &ln, const std::pair<db::Coord, db::Coord> &wxy, double dbu)
{ {
if (wxy.first == wxy.second) { // This implementation assumes the "preferred width" is controlling the default extension and it is
db::Coord de = db::coord_traits<db::Coord>::rounded (m_lef_importer.layer_ext (ln, wxy.first * 0.5 * dbu) / dbu); // identical to the minimum effective width. This is true if "LEF58_MINWIDTH" with "WRONGDIRECTION" is
return std::make_pair (de, de); // used in the proposed way. Which is to specify a larger width for the "wrong" direction.
} else { db::Coord de = db::coord_traits<db::Coord>::rounded (m_lef_importer.layer_ext (ln, std::min (wxy.first, wxy.second) * 0.5 * dbu) / dbu);
#if 0 return std::make_pair (de, de);
// 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. void
db::Coord dex = db::coord_traits<db::Coord>::rounded (m_lef_importer.layer_ext (ln, wxy.second * 0.5 * dbu) / dbu); DEFImporter::read_diearea (db::Layout &layout, db::Cell &design, double scale)
db::Coord dey = db::coord_traits<db::Coord>::rounded (m_lef_importer.layer_ext (ln, wxy.first * 0.5 * dbu) / dbu); {
return std::make_pair (dex, dey); std::vector<db::DPoint> points;
#else
// This implementation picks the default extension according to the specified wire width (which is the minimum while (! test (";")) {
// of wx and wy) test ("(");
db::Coord de = db::coord_traits<db::Coord>::rounded (m_lef_importer.layer_ext (ln, std::min (wxy.first, wxy.second) * 0.5 * dbu) / dbu); double x = get_double ();
return std::make_pair (de, de); double y = get_double ();
#endif points.push_back (db::DPoint (x * scale, y * scale));
test (")");
} }
if (points.size () >= 2) {
// create outline shape
std::pair <bool, unsigned int> 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<db::Coord>::rounded (w);
}
}
// parse over the rest
while (! peek ("+") && ! peek ("-") && ! peek (";")) {
take ();
}
}
test (";");
}
test ("END");
test ("NONDEFAULTRULES");
} }
void void
@ -231,31 +290,7 @@ DEFImporter::do_read (db::Layout &layout)
} else if (test ("DIEAREA")) { } else if (test ("DIEAREA")) {
std::vector<db::DPoint> points; read_diearea (layout, design, scale);
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 <bool, unsigned int> 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));
}
}
}
} else if (test ("PROPERTYDEFINITIONS")) { } else if (test ("PROPERTYDEFINITIONS")) {
// read over PROPERTYDEFINITIONS sections // read over PROPERTYDEFINITIONS sections
@ -265,41 +300,7 @@ DEFImporter::do_read (db::Layout &layout)
} else if (test ("NONDEFAULTRULES")) { } else if (test ("NONDEFAULTRULES")) {
// read NONDEFAULTRULES sections read_nondefaultrules (scale);
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");
} else if (test ("REGIONS")) { } else if (test ("REGIONS")) {

View File

@ -61,13 +61,15 @@ protected:
private: private:
LEFImporter m_lef_importer; LEFImporter m_lef_importer;
std::map<std::string, std::map<std::string, double> > m_nondefault_widths; std::map<std::string, std::map<std::string, db::Coord> > m_nondefault_widths;
db::FTrans get_orient (bool optional); db::FTrans get_orient (bool optional);
void read_polygon (db::Polygon &poly, double scale); void read_polygon (db::Polygon &poly, double scale);
void read_rect (db::Polygon &poly, double scale); void read_rect (db::Polygon &poly, double scale);
std::pair<Coord, Coord> get_wire_width_for_rule(const std::string &rule, const std::string &ln, double dbu); std::pair<Coord, Coord> get_wire_width_for_rule(const std::string &rule, const std::string &ln, double dbu);
std::pair<db::Coord, db::Coord> get_def_ext (const std::string &ln, const std::pair<db::Coord, db::Coord> &wxy, double dbu); std::pair<db::Coord, db::Coord> get_def_ext (const std::string &ln, const std::pair<db::Coord, db::Coord> &wxy, double dbu);
void read_diearea (db::Layout &layout, db::Cell &design, double scale);
void read_nondefaultrules (double scale);
}; };
} }

View File

@ -76,12 +76,12 @@ LEFImporter::min_layer_width (const std::string &layer) const
} }
} }
double std::pair<double, double>
LEFImporter::layer_width (const std::string &layer, const std::string &nondefaultrule, double def_width) const LEFImporter::layer_width (const std::string &layer, const std::string &nondefaultrule, const std::pair<double, double> &def_width) const
{ {
std::map<std::string, std::map<std::string, double> >::const_iterator nd = m_nondefault_widths.find (nondefaultrule); std::map<std::string, std::map<std::string, std::pair<double, double> > >::const_iterator nd = m_nondefault_widths.find (nondefaultrule);
std::map<std::string, double>::const_iterator l; std::map<std::string, std::pair<double, double> >::const_iterator l;
bool has_width = false; bool has_width = false;
if (! nondefaultrule.empty () && nd != m_nondefault_widths.end ()) { 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; w = 0.0;
std::map<std::string, double>::const_iterator dw = m_default_widths.find (layer_name); std::map<std::string, std::pair<double, double> >::const_iterator dw = m_default_widths.find (layer_name);
if (dw != m_default_widths.end ()) { if (dw != m_default_widths.end ()) {
w = dw->second; w = dw->second.first;
} }
while (! test (";")) { while (! test (";")) {
@ -388,7 +388,7 @@ LEFImporter::read_nondefaultrule (db::Layout & /*layout*/)
if (test ("WIDTH")) { if (test ("WIDTH")) {
double w = get_double (); double w = get_double ();
test (";"); test (";");
m_nondefault_widths[n][l] = w; m_nondefault_widths[n][l] = std::make_pair (w, w);
} else { } else {
while (! test (";")) { while (! test (";")) {
take (); take ();
@ -590,7 +590,8 @@ LEFImporter::read_layer (Layout & /*layout*/)
{ {
std::string ln = get (); std::string ln = get ();
double wmin = 0.0, wmin_wrongdir = 0.0; 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); register_layer (ln);
@ -615,8 +616,12 @@ LEFImporter::read_layer (Layout & /*layout*/)
} else if (test ("WIDTH")) { } else if (test ("WIDTH")) {
double w = get_double (); w = get_double ();
m_default_widths.insert (std::make_pair (ln, w)); expect (";");
} else if (test ("MINWIDTH")) {
wmin = get_double ();
expect (";"); expect (";");
} else if (test ("DIRECTION")) { } else if (test ("DIRECTION")) {
@ -629,8 +634,8 @@ LEFImporter::read_layer (Layout & /*layout*/)
} else if (test ("WIREEXTENSION")) { } else if (test ("WIREEXTENSION")) {
double w = get_double (); double v = get_double ();
m_default_ext.insert (std::make_pair (ln, w)); m_default_ext.insert (std::make_pair (ln, v));
expect (";"); expect (";");
} else if (test ("ACCURRENTDENSITY")) { } else if (test ("ACCURRENTDENSITY")) {
@ -656,17 +661,32 @@ LEFImporter::read_layer (Layout & /*layout*/)
// Cadence extension // Cadence extension
tl::Extractor ex (value.to_string ()); tl::Extractor ex (value.to_string ());
double mw = 0.0; double v = 0.0;
if (ex.test ("MINWIDTH") && ex.try_read (mw)) { if (ex.test ("MINWIDTH") && ex.try_read (v)) {
if (ex.test ("WRONGDIRECTION")) { if (ex.test ("WRONGDIRECTION")) {
wmin_wrongdir = mw; wmin_wrongdir = v;
} else { } 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 { } else {
while (! test (";")) { 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 (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); std::swap (wmin, wmin_wrongdir);
} }

View File

@ -77,7 +77,7 @@ public:
* The nondefaultrule name gives the name of the nondefaultrule or an empty string if * The nondefaultrule name gives the name of the nondefaultrule or an empty string if
* none is requested. * none is requested.
*/ */
double layer_width (const std::string &layer, const std::string &nondefaultrule, double def_width = 0.0) const; std::pair<double, double> layer_width (const std::string &layer, const std::string &nondefaultrule, const std::pair<double, double> &def_width = std::make_pair (0.0, 0.0)) const;
/** /**
* @brief Get the extension for a layer with the given name * @brief Get the extension for a layer with the given name
@ -121,8 +121,8 @@ protected:
void do_read (db::Layout &layout); void do_read (db::Layout &layout);
private: private:
std::map<std::string, std::map<std::string, double> > m_nondefault_widths; std::map<std::string, std::map<std::string, std::pair<double, double> > > m_nondefault_widths;
std::map<std::string, double> m_default_widths; std::map<std::string, std::pair<double, double> > m_default_widths;
std::map<std::string, double> m_default_ext; std::map<std::string, double> m_default_ext;
std::map<std::string, std::pair<double, double> > m_min_widths; std::map<std::string, std::pair<double, double> > m_min_widths;
std::map<std::string, db::Cell *> m_macros_by_name; std::map<std::string, db::Cell *> m_macros_by_name;

View File

@ -284,3 +284,14 @@ TEST(106_wrongdirection)
{ {
run_test (_this, "wrongdirection", "lef:test.lef+def:test.def", "au.oas.gz", default_options (), false); 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);
}

BIN
testdata/lefdef/scanchain/au.oas.gz vendored Normal file

Binary file not shown.

32
testdata/lefdef/scanchain/test.def vendored Normal file
View File

@ -0,0 +1,32 @@
VERSION 5.8 ;
DIVIDERCHAR "/" ;
BUSBITCHARS "[]" ;
DESIGN chip_top ;
UNITS DISTANCE MICRONS 1000 ;
DIEAREA ( 0 0 ) ( 8729280 8199360 ) ;
SCANCHAINS 9992 ;
- chain1
+ PARTITION part/Y_45_45_0.720000
+ START whereever/anchor_buf_8 Y
+ FLOATING
dumdidum/_reg_1_reg_2_ ( IN SI ) ( OUT Q )
dumdidum/_reg_1_reg_2_ ( IN SI ) ( OUT Q )
dumdidum/_reg_1_reg_7_ ( IN SI ) ( OUT Q )
dumdidum/_reg_1_reg_8_ ( IN SI ) ( OUT Q )
dumdidum/_reg_1_reg_5_ ( IN SI ) ( OUT Q )
dumdidum/_reg_1_reg_9_ ( IN SI ) ( OUT Q )
dumdidum/_reg_1_reg_6_ ( IN SI ) ( OUT Q )
dumdidum/_reg_1_reg_4_ ( IN SI ) ( OUT Q )
dumdidum/_reg_1_reg_7_ ( IN SI ) ( OUT Q )
dumdidum/_reg_1_reg_1_ ( IN SI ) ( OUT Q )
dumdidum/_reg_1_reg_3_ ( IN SI ) ( OUT Q )
dumdidum/_reg_1_reg_1_ ( IN SI ) ( OUT Q )
dumdidum/_reg_1_reg_0_ ( IN SI ) ( OUT Q )
dumdidum/_reg_1_reg_4_ ( IN SI ) ( OUT Q )
dumdidum/_reg_1_reg_0_ ( IN SI ) ( OUT Q )
dumdidum/_reg_1_reg_6_ ( IN SI ) ( OUT Q )
dumdidum/_reg_1_reg_3_ ( IN SI ) ( OUT Q )
dumdidum/_reg_1_reg_5_ ( IN SI ) ( OUT Q )
+ STOP somewhere/LOCKUP D ;
END SCANCHAINS
END DESIGN

BIN
testdata/lefdef/specialwidths/au.oas.gz vendored Normal file

Binary file not shown.

19
testdata/lefdef/specialwidths/test.def vendored Normal file
View File

@ -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

43
testdata/lefdef/specialwidths/test.lef vendored Normal file
View File

@ -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