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

Added/updated some tests, some refactoring.
This commit is contained in:
Matthias Koefferlein
2020-04-05 21:49:36 +02:00
parent 4a24b727d5
commit f11a3a0dd5
10 changed files with 245 additions and 103 deletions
@@ -139,15 +139,17 @@ struct Group
std::pair<db::Coord, db::Coord>
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
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 ()) {
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 ()) {
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_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>
DEFImporter::get_def_ext (const std::string &ln, const std::pair<db::Coord, db::Coord> &wxy, double dbu)
{
if (wxy.first == wxy.second) {
db::Coord de = db::coord_traits<db::Coord>::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<db::Coord>::rounded (m_lef_importer.layer_ext (ln, wxy.second * 0.5 * dbu) / dbu);
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);
#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<db::Coord>::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<db::Coord>::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<db::DPoint> 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 <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
@@ -231,31 +290,7 @@ DEFImporter::do_read (db::Layout &layout)
} else if (test ("DIEAREA")) {
std::vector<db::DPoint> 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 <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));
}
}
}
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")) {
@@ -61,13 +61,15 @@ protected:
private:
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);
void read_polygon (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<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);
};
}
@@ -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<double, double>
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;
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<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 ()) {
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);
}
@@ -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<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
@@ -121,8 +121,8 @@ protected:
void do_read (db::Layout &layout);
private:
std::map<std::string, std::map<std::string, double> > m_nondefault_widths;
std::map<std::string, double> m_default_widths;
std::map<std::string, std::map<std::string, std::pair<double, double> > > m_nondefault_widths;
std::map<std::string, std::pair<double, double> > m_default_widths;
std::map<std::string, double> m_default_ext;
std::map<std::string, std::pair<double, double> > m_min_widths;
std::map<std::string, db::Cell *> m_macros_by_name;
@@ -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);
}