mirror of https://github.com/KLayout/klayout.git
Fixing issue #2075 (strm2oas ignores def net routing wire extensions)
This commit is contained in:
parent
d1dc885235
commit
aba1b30c8d
|
|
@ -30,6 +30,8 @@
|
||||||
namespace db
|
namespace db
|
||||||
{
|
{
|
||||||
|
|
||||||
|
static const std::pair<db::Coord, db::Coord> ext_not_set = std::make_pair (std::numeric_limits<db::Coord>::min (), std::numeric_limits<db::Coord>::min ());
|
||||||
|
|
||||||
struct DEFImporterGroup
|
struct DEFImporterGroup
|
||||||
{
|
{
|
||||||
DEFImporterGroup (const std::string &n, const std::string &rn, const std::vector<tl::GlobPattern> &m)
|
DEFImporterGroup (const std::string &n, const std::string &rn, const std::vector<tl::GlobPattern> &m)
|
||||||
|
|
@ -133,7 +135,7 @@ DEFImporter::get_def_ext (const std::string & /*ln*/, const std::pair<db::Coord,
|
||||||
return std::make_pair (de, de);
|
return std::make_pair (de, de);
|
||||||
#else
|
#else
|
||||||
// This implementation follows the LEFDEF 5.8 spec saying the "default extension is half the wire width":
|
// This implementation follows the LEFDEF 5.8 spec saying the "default extension is half the wire width":
|
||||||
db::Coord de = std::min (wxy.first, wxy.second) / 2;
|
auto de = std::min (wxy.second, wxy.first) / 2;
|
||||||
return std::make_pair (de, de);
|
return std::make_pair (de, de);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
@ -355,28 +357,46 @@ DEFImporter::produce_routing_geometry (db::Cell &design, const Polygon *style, u
|
||||||
bool was_path_before = false;
|
bool was_path_before = false;
|
||||||
|
|
||||||
std::vector<db::Point>::const_iterator pt = pts.begin ();
|
std::vector<db::Point>::const_iterator pt = pts.begin ();
|
||||||
|
std::vector<std::pair<db::Coord, db::Coord> >::const_iterator ex = ext.begin ();
|
||||||
|
|
||||||
while (pt != pts.end ()) {
|
while (pt != pts.end ()) {
|
||||||
|
|
||||||
std::vector<db::Point>::const_iterator pt0 = pt;
|
auto pt0 = pt;
|
||||||
|
auto ex0 = ex;
|
||||||
++pt;
|
++pt;
|
||||||
|
++ex;
|
||||||
if (pt == pts.end ()) {
|
if (pt == pts.end ()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool multipart = false;
|
bool multipart = false;
|
||||||
if (is_isotropic) {
|
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;
|
++pt;
|
||||||
|
++ex;
|
||||||
multipart = true;
|
multipart = true;
|
||||||
}
|
}
|
||||||
if (multipart) {
|
if (multipart) {
|
||||||
--pt;
|
--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;
|
db::Coord wxy, wxy_perp;
|
||||||
|
|
||||||
|
|
@ -388,33 +408,27 @@ DEFImporter::produce_routing_geometry (db::Cell &design, const Polygon *style, u
|
||||||
wxy_perp = w.second;
|
wxy_perp = w.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
// compute begin extension
|
// compute begin and end extensions
|
||||||
db::Coord be = 0;
|
db::Coord be = 0;
|
||||||
if (pt0 == pts.begin ()) {
|
if (*ex0 != ext_not_set) {
|
||||||
if (pt0->x () == pt0 [1].x ()) {
|
be = (pt0->x () == pt0 [1].x ()) ? ex0->second : ex0->first;
|
||||||
be = ext.front ().second;
|
|
||||||
} else {
|
|
||||||
be = ext.front ().first;
|
|
||||||
}
|
|
||||||
} else if (was_path_before) {
|
} else if (was_path_before) {
|
||||||
// provides the overlap to the previous segment
|
// provides the overlap to the previous segment
|
||||||
be = wxy_perp / 2;
|
be = wxy_perp / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// compute end extension
|
|
||||||
db::Coord ee = 0;
|
db::Coord ee = 0;
|
||||||
if (pt + 1 == pts.end ()) {
|
if (*ex != ext_not_set) {
|
||||||
if (pt [-1].x () == pt->x ()) {
|
ee = (pt [-1].x () == pt->x ()) ? ex->second : ex->first;
|
||||||
ee = ext.back ().second;
|
|
||||||
} else {
|
|
||||||
ee = ext.back ().first;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto pt_from = pt0;
|
auto pt_from = pt0;
|
||||||
auto pt_to = pt + 1;
|
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_from_split = pt_from;
|
||||||
auto pt_to_split = pt_to;
|
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;
|
const std::string *rulename = 0;
|
||||||
|
|
||||||
std::pair<db::Coord, db::Coord> w (0, 0);
|
std::pair<db::Coord, db::Coord> w (0, 0);
|
||||||
if (specialnets) {
|
|
||||||
db::Coord n = db::coord_traits<db::Coord>::rounded (get_double () * scale);
|
|
||||||
w = std::make_pair (n, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
const db::Polygon *style = 0;
|
const db::Polygon *style = 0;
|
||||||
|
|
||||||
|
|
@ -564,6 +574,9 @@ DEFImporter::read_single_net (std::string &nondefaultrule, Layout &layout, db::C
|
||||||
|
|
||||||
if (specialnets) {
|
if (specialnets) {
|
||||||
|
|
||||||
|
db::Coord n = db::coord_traits<db::Coord>::rounded (get_double () * scale);
|
||||||
|
w = std::make_pair (n, n);
|
||||||
|
|
||||||
while (test ("+")) {
|
while (test ("+")) {
|
||||||
|
|
||||||
if (test ("STYLE")) {
|
if (test ("STYLE")) {
|
||||||
|
|
@ -598,11 +611,17 @@ DEFImporter::read_single_net (std::string &nondefaultrule, Layout &layout, db::C
|
||||||
rulename = &nondefaultrule;
|
rulename = &nondefaultrule;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<db::Coord, db::Coord> def_ext (0, 0);
|
|
||||||
|
|
||||||
if (! specialnets) {
|
if (! specialnets) {
|
||||||
w = get_wire_width_for_rule (*rulename, ln, layout.dbu ());
|
w = get_wire_width_for_rule (*rulename, ln, layout.dbu ());
|
||||||
def_ext = get_def_ext (ln, w, layout.dbu ());
|
}
|
||||||
|
|
||||||
|
// default extension for first and last point
|
||||||
|
std::pair<db::Coord, db::Coord> def_ext (0, 0);
|
||||||
|
std::pair<db::Coord, db::Coord> def_ext_conn = get_def_ext (ln, w, layout.dbu ());
|
||||||
|
|
||||||
|
if (! specialnets) {
|
||||||
|
// first and last extensions are half width by default for routed nets
|
||||||
|
def_ext = def_ext_conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<int, db::Polygon>::const_iterator s = m_styles.find (sn);
|
std::map<int, db::Polygon>::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 ();
|
y = get_double ();
|
||||||
}
|
}
|
||||||
pts.push_back (db::Point (db::DPoint (x * scale, y * scale)));
|
pts.push_back (db::Point (db::DPoint (x * scale, y * scale)));
|
||||||
std::pair<db::Coord, db::Coord> ee = def_ext;
|
std::pair<db::Coord, db::Coord> ee = ext_not_set;
|
||||||
if (! peek (")")) {
|
if (! peek (")")) {
|
||||||
db::Coord e = db::coord_traits<db::Coord>::rounded (get_double () * scale);
|
db::Coord e = db::coord_traits<db::Coord>::rounded (get_double () * scale);
|
||||||
ee.first = ee.second = e;
|
ee.first = ee.second = e;
|
||||||
|
|
@ -706,10 +725,20 @@ DEFImporter::read_single_net (std::string &nondefaultrule, Layout &layout, db::C
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pts.size () > 1) {
|
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 <unsigned int> dl = open_layer (layout, ln, specialnets ? SpecialRouting : Routing, mask);
|
std::set <unsigned int> dl = open_layer (layout, ln, specialnets ? SpecialRouting : Routing, mask);
|
||||||
for (std::set<unsigned int>::const_iterator l = dl.begin (); l != dl.end (); ++l) {
|
for (std::set<unsigned int>::const_iterator l = dl.begin (); l != dl.end (); ++l) {
|
||||||
produce_routing_geometry (design, style, *l, prop_id, pts, ext, w);
|
produce_routing_geometry (design, style, *l, prop_id, pts, ext, w);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// continue a segment with the current point and the new mask
|
// continue a segment with the current point and the new mask
|
||||||
|
|
|
||||||
|
|
@ -432,7 +432,7 @@ TEST(def16)
|
||||||
// (complete example)
|
// (complete example)
|
||||||
db::LEFDEFReaderOptions opt = default_options ();
|
db::LEFDEFReaderOptions opt = default_options ();
|
||||||
opt.set_macro_resolution_mode (1);
|
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)
|
TEST(100)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue