mirror of https://github.com/KLayout/klayout.git
Bugfix: MINWIDTH ... WRONGDIRECTION wasn't considering DIRECTION VERTICAL
Added/updated some tests, some refactoring.
This commit is contained in:
parent
4a24b727d5
commit
f11a3a0dd5
|
|
@ -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)
|
||||
// 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);
|
||||
#endif
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -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
|
||||
Binary file not shown.
|
|
@ -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
|
||||
|
|
@ -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
|
||||
Loading…
Reference in New Issue