mirror of https://github.com/KLayout/klayout.git
Tried to implement MINWIDTH .. WRONGDIRECTION in LEF58_MINWIDTH property
This commit is contained in:
parent
bcaf28c94c
commit
4a24b727d5
|
|
@ -136,10 +136,10 @@ struct Group
|
||||||
std::vector<tl::GlobPattern> comp_match;
|
std::vector<tl::GlobPattern> comp_match;
|
||||||
};
|
};
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
double w = db::coord_traits<db::Coord>::rounded (m_lef_importer.layer_width (ln, rulename, 0.0) / dbu);
|
db::Coord w = db::coord_traits<db::Coord>::rounded (m_lef_importer.layer_width (ln, rulename, 0.0) / dbu);
|
||||||
|
|
||||||
// try to find local nondefault rule
|
// try to find local nondefault rule
|
||||||
if (! rulename.empty ()) {
|
if (! rulename.empty ()) {
|
||||||
|
|
@ -152,7 +152,34 @@ DEFImporter::get_wire_width_for_rule (const std::string &rulename, const std::st
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return w;
|
std::pair<double, double> min_wxy = m_lef_importer.min_layer_width (ln);
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -501,9 +528,10 @@ DEFImporter::do_read (db::Layout &layout)
|
||||||
taperrule.clear ();
|
taperrule.clear ();
|
||||||
const std::string *rulename = 0;
|
const std::string *rulename = 0;
|
||||||
|
|
||||||
db::Coord w = 0;
|
std::pair<db::Coord, db::Coord> w (0, 0);
|
||||||
if (specialnets) {
|
if (specialnets) {
|
||||||
w = db::coord_traits<db::Coord>::rounded (get_double () * scale);
|
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;
|
||||||
|
|
@ -544,11 +572,11 @@ DEFImporter::do_read (db::Layout &layout)
|
||||||
rulename = &nondefaultrule;
|
rulename = &nondefaultrule;
|
||||||
}
|
}
|
||||||
|
|
||||||
db::Coord def_ext = 0;
|
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 = db::coord_traits<db::Coord>::rounded (m_lef_importer.layer_ext (ln, w * 0.5 * layout.dbu ()) / layout.dbu ());
|
def_ext = get_def_ext (ln, w, layout.dbu ());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<int, db::Polygon>::const_iterator s = styles.find (sn);
|
std::map<int, db::Polygon>::const_iterator s = styles.find (sn);
|
||||||
|
|
@ -556,7 +584,7 @@ DEFImporter::do_read (db::Layout &layout)
|
||||||
style = &s->second;
|
style = &s->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<db::Coord> ext;
|
std::vector<std::pair<db::Coord, db::Coord> > ext;
|
||||||
std::vector<db::Point> pts;
|
std::vector<db::Point> pts;
|
||||||
|
|
||||||
double x = 0.0, y = 0.0;
|
double x = 0.0, y = 0.0;
|
||||||
|
|
@ -629,11 +657,12 @@ DEFImporter::do_read (db::Layout &layout)
|
||||||
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)));
|
||||||
db::Coord e = def_ext;
|
std::pair<db::Coord, db::Coord> ee = def_ext;
|
||||||
if (! peek (")")) {
|
if (! peek (")")) {
|
||||||
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;
|
||||||
}
|
}
|
||||||
ext.push_back (e);
|
ext.push_back (ee);
|
||||||
|
|
||||||
test (")");
|
test (")");
|
||||||
|
|
||||||
|
|
@ -648,8 +677,11 @@ DEFImporter::do_read (db::Layout &layout)
|
||||||
|
|
||||||
// Use the default style (octagon "pen" for non-manhattan segments, paths for
|
// Use the default style (octagon "pen" for non-manhattan segments, paths for
|
||||||
// horizontal/vertical segments).
|
// horizontal/vertical segments).
|
||||||
|
// Manhattan paths are stitched together from two-point paths if they
|
||||||
|
|
||||||
db::Coord e = std::max (ext.front (), ext.back ());
|
std::pair<db::Coord, db::Coord> e = std::max (ext.front (), ext.back ());
|
||||||
|
bool is_isotropic = (e.first == e.second && w.first == w.second);
|
||||||
|
bool was_path = false;
|
||||||
|
|
||||||
std::vector<db::Point>::const_iterator pt = pts.begin ();
|
std::vector<db::Point>::const_iterator pt = pts.begin ();
|
||||||
while (pt != pts.end ()) {
|
while (pt != pts.end ()) {
|
||||||
|
|
@ -657,11 +689,27 @@ DEFImporter::do_read (db::Layout &layout)
|
||||||
std::vector<db::Point>::const_iterator pt0 = pt;
|
std::vector<db::Point>::const_iterator pt0 = pt;
|
||||||
do {
|
do {
|
||||||
++pt;
|
++pt;
|
||||||
} while (pt != pts.end () && (pt[-1].x () == pt[0].x () || pt[-1].y () == pt[0].y()));
|
} while (pt != pts.end () && is_isotropic && (pt[-1].x () == pt[0].x () || pt[-1].y () == pt[0].y()));
|
||||||
|
|
||||||
if (pt - pt0 > 1) {
|
if (pt - pt0 > 1 || pt0->x () == pt0[1].x () || pt0->y () == pt0[0].y()) {
|
||||||
|
|
||||||
db::Path p (pt0, pt, w, pt0 == pts.begin () ? e : 0, pt == pts.end () ? e : 0, false);
|
if (pt - pt0 == 1) {
|
||||||
|
++pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
db::Coord wxy, wxy_perp, exy;
|
||||||
|
|
||||||
|
if (pt0->x () == pt0 [1].x ()) {
|
||||||
|
wxy = w.second;
|
||||||
|
wxy_perp = w.first;
|
||||||
|
exy = e.second;
|
||||||
|
} else {
|
||||||
|
wxy = w.first;
|
||||||
|
wxy_perp = w.second;
|
||||||
|
exy = e.first;
|
||||||
|
}
|
||||||
|
|
||||||
|
db::Path p (pt0, pt, wxy, pt0 == pts.begin () ? exy : (was_path ? wxy_perp / 2 : 0), pt == pts.end () ? exy : 0, false);
|
||||||
if (prop_id != 0) {
|
if (prop_id != 0) {
|
||||||
design.shapes (dl.second).insert (db::object_with_properties<db::Path> (p, prop_id));
|
design.shapes (dl.second).insert (db::object_with_properties<db::Path> (p, prop_id));
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -674,10 +722,16 @@ DEFImporter::do_read (db::Layout &layout)
|
||||||
|
|
||||||
--pt;
|
--pt;
|
||||||
|
|
||||||
} else if (pt != pts.end ()) {
|
was_path = true;
|
||||||
|
|
||||||
db::Coord s = (w + 1) / 2;
|
} else {
|
||||||
db::Coord t = db::Coord (ceil (w * (M_SQRT2 - 1) / 2));
|
|
||||||
|
if (! is_isotropic) {
|
||||||
|
warn("Anisotropic wire widths not supported for diagonal wires");
|
||||||
|
}
|
||||||
|
|
||||||
|
db::Coord s = (w.first + 1) / 2;
|
||||||
|
db::Coord t = db::Coord (ceil (w.first * (M_SQRT2 - 1) / 2));
|
||||||
|
|
||||||
db::Point octagon[8] = {
|
db::Point octagon[8] = {
|
||||||
db::Point (-s, t),
|
db::Point (-s, t),
|
||||||
|
|
@ -700,6 +754,8 @@ DEFImporter::do_read (db::Layout &layout)
|
||||||
design.shapes (dl.second).insert (p);
|
design.shapes (dl.second).insert (p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
was_path = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -766,7 +822,7 @@ DEFImporter::do_read (db::Layout &layout)
|
||||||
|
|
||||||
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 = db::coord_traits<db::Coord>::rounded (m_lef_importer.layer_ext (ln, w * 0.5 * layout.dbu ()) / layout.dbu ());
|
def_ext = get_def_ext (ln, w, layout.dbu ());
|
||||||
}
|
}
|
||||||
|
|
||||||
// continue a segment with the current point and the new layer
|
// continue a segment with the current point and the new layer
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,8 @@ private:
|
||||||
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);
|
||||||
db::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);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -531,7 +531,23 @@ LEFDEFImporter::expect (const std::string &token)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
double
|
void
|
||||||
|
LEFDEFImporter::expect (const std::string &token1, const std::string &token2)
|
||||||
|
{
|
||||||
|
if (! test (token1) && ! test (token2)) {
|
||||||
|
error ("Expected token: " + token1 + " or " + token2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LEFDEFImporter::expect (const std::string &token1, const std::string &token2, const std::string &token3)
|
||||||
|
{
|
||||||
|
if (! test (token1) && ! test (token2) && ! test (token3)) {
|
||||||
|
error ("Expected token: " + token1 + ", " + token2 + " or " + token3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double
|
||||||
LEFDEFImporter::get_double ()
|
LEFDEFImporter::get_double ()
|
||||||
{
|
{
|
||||||
if (m_last_token.empty ()) {
|
if (m_last_token.empty ()) {
|
||||||
|
|
|
||||||
|
|
@ -642,6 +642,16 @@ protected:
|
||||||
*/
|
*/
|
||||||
void expect (const std::string &token);
|
void expect (const std::string &token);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Test whether the next token matches one of the given ones and raise an error if it does not
|
||||||
|
*/
|
||||||
|
void expect (const std::string &token1, const std::string &token2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Test whether the next token matches one of the given ones and raise an error if it does not
|
||||||
|
*/
|
||||||
|
void expect (const std::string &token, const std::string &token2, const std::string &token3);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets the next token
|
* @brief Gets the next token
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,17 @@ LEFImporter::layer_ext (const std::string &layer, double def_ext) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::pair<double, double>
|
||||||
|
LEFImporter::min_layer_width (const std::string &layer) const
|
||||||
|
{
|
||||||
|
std::map<std::string, std::pair<double, double> >::const_iterator l = m_min_widths.find (layer);
|
||||||
|
if (l != m_min_widths.end ()) {
|
||||||
|
return l->second;
|
||||||
|
} else {
|
||||||
|
return std::make_pair (0.0, 0.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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, double def_width) const
|
||||||
{
|
{
|
||||||
|
|
@ -360,6 +371,431 @@ LEFImporter::read_geometries (db::Layout &layout, db::Cell &cell, LayerPurpose p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LEFImporter::read_nondefaultrule (db::Layout & /*layout*/)
|
||||||
|
{
|
||||||
|
// read NONDEFAULTRULE sections
|
||||||
|
std::string n = get ();
|
||||||
|
|
||||||
|
while (! test ("END") || ! test (n)) {
|
||||||
|
|
||||||
|
if (test ("LAYER")) {
|
||||||
|
|
||||||
|
std::string l = get ();
|
||||||
|
|
||||||
|
// read the width for the layer
|
||||||
|
while (! test ("END")) {
|
||||||
|
if (test ("WIDTH")) {
|
||||||
|
double w = get_double ();
|
||||||
|
test (";");
|
||||||
|
m_nondefault_widths[n][l] = w;
|
||||||
|
} else {
|
||||||
|
while (! test (";")) {
|
||||||
|
take ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test (l);
|
||||||
|
|
||||||
|
} else if (test ("VIA")) {
|
||||||
|
|
||||||
|
// ignore VIA statements
|
||||||
|
std::string v = get ();
|
||||||
|
while (! test ("END") || ! test (v)) {
|
||||||
|
take ();
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
while (! test (";")) {
|
||||||
|
take ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LEFImporter::read_viadef_by_rule (Layout &layout, db::Cell &cell, ViaDesc &via_desc, const std::string & /*n*/)
|
||||||
|
{
|
||||||
|
db::Vector cutsize, cutspacing;
|
||||||
|
db::Vector be, te;
|
||||||
|
db::Vector bo, to;
|
||||||
|
db::Point offset;
|
||||||
|
int rows = 1, columns = 1;
|
||||||
|
std::string pattern;
|
||||||
|
|
||||||
|
std::vector<std::pair<std::string, std::vector<db::Polygon> > > geometry;
|
||||||
|
geometry.push_back (std::pair<std::string, std::vector<db::Polygon> > ());
|
||||||
|
geometry.push_back (std::pair<std::string, std::vector<db::Polygon> > ());
|
||||||
|
geometry.push_back (std::pair<std::string, std::vector<db::Polygon> > ());
|
||||||
|
|
||||||
|
while (! test ("END")) {
|
||||||
|
|
||||||
|
double x, y;
|
||||||
|
|
||||||
|
if (test ("CUTSIZE")) {
|
||||||
|
|
||||||
|
x = get_double ();
|
||||||
|
y = get_double ();
|
||||||
|
cutsize = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ()));
|
||||||
|
|
||||||
|
test (";");
|
||||||
|
|
||||||
|
} else if (test ("CUTSPACING")) {
|
||||||
|
|
||||||
|
x = get_double ();
|
||||||
|
y = get_double ();
|
||||||
|
cutspacing = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ()));
|
||||||
|
|
||||||
|
test (";");
|
||||||
|
|
||||||
|
} else if (test ("ORIGIN")) {
|
||||||
|
|
||||||
|
x = get_double ();
|
||||||
|
y = get_double ();
|
||||||
|
offset = db::Point (db::DPoint (x / layout.dbu (), y / layout.dbu ()));
|
||||||
|
|
||||||
|
test (";");
|
||||||
|
|
||||||
|
} else if (test ("ENCLOSURE")) {
|
||||||
|
|
||||||
|
x = get_double ();
|
||||||
|
y = get_double ();
|
||||||
|
be = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ()));
|
||||||
|
|
||||||
|
x = get_double ();
|
||||||
|
y = get_double ();
|
||||||
|
te = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ()));
|
||||||
|
|
||||||
|
test (";");
|
||||||
|
|
||||||
|
} else if (test ("OFFSET")) {
|
||||||
|
|
||||||
|
x = get_double ();
|
||||||
|
y = get_double ();
|
||||||
|
bo = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ()));
|
||||||
|
|
||||||
|
x = get_double ();
|
||||||
|
y = get_double ();
|
||||||
|
to = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ()));
|
||||||
|
|
||||||
|
test (";");
|
||||||
|
|
||||||
|
} else if (test ("ROWCOL")) {
|
||||||
|
|
||||||
|
rows = get_long ();
|
||||||
|
columns = get_long ();
|
||||||
|
|
||||||
|
test (";");
|
||||||
|
|
||||||
|
} else if (test ("PATTERN")) {
|
||||||
|
|
||||||
|
pattern = get ();
|
||||||
|
|
||||||
|
test (";");
|
||||||
|
|
||||||
|
} else if (test ("LAYERS")) {
|
||||||
|
|
||||||
|
via_desc.m1 = geometry[0].first = get ();
|
||||||
|
geometry[1].first = get ();
|
||||||
|
via_desc.m2 = geometry[2].first = get ();
|
||||||
|
|
||||||
|
test (";");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
while (! test (";")) {
|
||||||
|
take ();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
create_generated_via (geometry [0].second, geometry [1].second, geometry [2].second,
|
||||||
|
cutsize, cutspacing, be, te, bo, to, offset, rows, columns, pattern);
|
||||||
|
|
||||||
|
for (std::vector<std::pair<std::string, std::vector<db::Polygon> > >::const_iterator g = geometry.begin (); g != geometry.end (); ++g) {
|
||||||
|
std::pair <bool, unsigned int> dl = open_layer (layout, g->first, ViaGeometry);
|
||||||
|
if (dl.first) {
|
||||||
|
for (std::vector<db::Polygon>::const_iterator p = g->second.begin (); p != g->second.end (); ++p) {
|
||||||
|
cell.shapes (dl.second).insert (*p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LEFImporter::read_viadef_by_geometry (Layout &layout, db::Cell &cell, ViaDesc &via_desc, const std::string &n)
|
||||||
|
{
|
||||||
|
// ignore resistance spec
|
||||||
|
if (test ("RESISTANCE")) {
|
||||||
|
get_double ();
|
||||||
|
test (";");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<std::string, db::Box> bboxes;
|
||||||
|
read_geometries (layout, cell, ViaGeometry, &bboxes);
|
||||||
|
|
||||||
|
// determine m1 and m2 layers
|
||||||
|
|
||||||
|
std::vector<std::string> routing_layers;
|
||||||
|
for (std::map<std::string, db::Box>::const_iterator b = bboxes.begin (); b != bboxes.end (); ++b) {
|
||||||
|
if (m_routing_layers.find (b->first) != m_routing_layers.end ()) {
|
||||||
|
routing_layers.push_back (b->first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (routing_layers.size () == 2) {
|
||||||
|
via_desc.m1 = routing_layers[0];
|
||||||
|
via_desc.m2 = routing_layers[1];
|
||||||
|
} else {
|
||||||
|
warn ("Can't determine routing layers for via: " + n);
|
||||||
|
}
|
||||||
|
|
||||||
|
reset_cellname ();
|
||||||
|
|
||||||
|
expect ("END");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LEFImporter::read_viadef (Layout &layout)
|
||||||
|
{
|
||||||
|
std::string n = get ();
|
||||||
|
|
||||||
|
// produce a cell for vias
|
||||||
|
std::string cellname = "VIA_" + n;
|
||||||
|
db::Cell &cell = layout.cell (layout.add_cell (cellname.c_str ()));
|
||||||
|
|
||||||
|
ViaDesc &via_desc = m_vias[n];
|
||||||
|
via_desc.cell = &cell;
|
||||||
|
|
||||||
|
while (test ("DEFAULT") || test ("TOPOFSTACKONLY"))
|
||||||
|
;
|
||||||
|
test (";");
|
||||||
|
|
||||||
|
if (test ("VIARULE")) {
|
||||||
|
read_viadef_by_rule (layout, cell, via_desc, n);
|
||||||
|
} else {
|
||||||
|
read_viadef_by_geometry (layout, cell, via_desc, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
test ("VIA");
|
||||||
|
expect (n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LEFImporter::read_layer (Layout & /*layout*/)
|
||||||
|
{
|
||||||
|
std::string ln = get ();
|
||||||
|
double wmin = 0.0, wmin_wrongdir = 0.0;
|
||||||
|
bool is_horizontal = true;
|
||||||
|
|
||||||
|
register_layer (ln);
|
||||||
|
|
||||||
|
// just extract the width from the layer - we need that as the default width for paths
|
||||||
|
while (! at_end ()) {
|
||||||
|
|
||||||
|
if (test ("END")) {
|
||||||
|
|
||||||
|
expect (ln);
|
||||||
|
break;
|
||||||
|
|
||||||
|
} else if (test ("TYPE")) {
|
||||||
|
|
||||||
|
if (test ("ROUTING")) {
|
||||||
|
m_routing_layers.insert (ln);
|
||||||
|
} else if (test ("CUT")) {
|
||||||
|
m_cut_layers.insert (ln);
|
||||||
|
} else {
|
||||||
|
get ();
|
||||||
|
}
|
||||||
|
expect (";");
|
||||||
|
|
||||||
|
} else if (test ("WIDTH")) {
|
||||||
|
|
||||||
|
double w = get_double ();
|
||||||
|
m_default_widths.insert (std::make_pair (ln, w));
|
||||||
|
expect (";");
|
||||||
|
|
||||||
|
} else if (test ("DIRECTION")) {
|
||||||
|
|
||||||
|
if (test ("HORIZONTAL")) {
|
||||||
|
is_horizontal = true;
|
||||||
|
} else {
|
||||||
|
expect ("VERTICAL", "DIAG45", "DIAG135");
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (test ("WIREEXTENSION")) {
|
||||||
|
|
||||||
|
double w = get_double ();
|
||||||
|
m_default_ext.insert (std::make_pair (ln, w));
|
||||||
|
expect (";");
|
||||||
|
|
||||||
|
} else if (test ("ACCURRENTDENSITY")) {
|
||||||
|
|
||||||
|
// ACCURRENTDENSITY needs some special attention because it can contain nested WIDTH
|
||||||
|
// blocks following a semicolon
|
||||||
|
take ();
|
||||||
|
if (test ("FREQUENCY")) {
|
||||||
|
while (! test ("TABLEENTRIES")) {
|
||||||
|
take ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (! test (";")) {
|
||||||
|
take ();
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (test ("PROPERTY")) {
|
||||||
|
|
||||||
|
std::string name = get ();
|
||||||
|
tl::Variant value = get ();
|
||||||
|
|
||||||
|
if (name == "LEF58_MINWIDTH") {
|
||||||
|
|
||||||
|
// Cadence extension
|
||||||
|
tl::Extractor ex (value.to_string ());
|
||||||
|
double mw = 0.0;
|
||||||
|
if (ex.test ("MINWIDTH") && ex.try_read (mw)) {
|
||||||
|
if (ex.test ("WRONGDIRECTION")) {
|
||||||
|
wmin_wrongdir = mw;
|
||||||
|
} else {
|
||||||
|
wmin = mw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
while (! test (";")) {
|
||||||
|
take ();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wmin > 0.0 || wmin_wrongdir > 0.0) {
|
||||||
|
|
||||||
|
if (! is_horizontal) {
|
||||||
|
std::swap (wmin, wmin_wrongdir);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_min_widths.insert (std::make_pair (ln, std::make_pair (wmin, wmin_wrongdir)));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LEFImporter::read_macro (Layout &layout)
|
||||||
|
{
|
||||||
|
std::string mn = get ();
|
||||||
|
set_cellname (mn);
|
||||||
|
|
||||||
|
db::Cell &cell = layout.cell (layout.add_cell (mn.c_str ()));
|
||||||
|
|
||||||
|
m_macros_by_name.insert (std::make_pair (mn, &cell));
|
||||||
|
|
||||||
|
db::Point origin;
|
||||||
|
db::Vector size;
|
||||||
|
|
||||||
|
// read the macro
|
||||||
|
while (! at_end ()) {
|
||||||
|
|
||||||
|
if (test ("END")) {
|
||||||
|
expect (mn);
|
||||||
|
break;
|
||||||
|
|
||||||
|
} else if (test ("ORIGIN")) {
|
||||||
|
|
||||||
|
double x = get_double ();
|
||||||
|
double y = get_double ();
|
||||||
|
expect (";");
|
||||||
|
origin = db::Point (db::DPoint (x / layout.dbu (), y / layout.dbu ()));
|
||||||
|
|
||||||
|
} else if (test ("SIZE")) {
|
||||||
|
|
||||||
|
double x = get_double ();
|
||||||
|
test ("BY");
|
||||||
|
double y = get_double ();
|
||||||
|
expect (";");
|
||||||
|
size = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ()));
|
||||||
|
|
||||||
|
} else if (test ("PIN")) {
|
||||||
|
|
||||||
|
std::string pn = get ();
|
||||||
|
std::string dir;
|
||||||
|
|
||||||
|
while (! at_end ()) {
|
||||||
|
if (test ("END")) {
|
||||||
|
break;
|
||||||
|
} else if (test ("DIRECTION")) {
|
||||||
|
dir = get ();
|
||||||
|
test (";");
|
||||||
|
} else if (test ("PORT")) {
|
||||||
|
|
||||||
|
// produce pin labels
|
||||||
|
// TODO: put a label on every single object?
|
||||||
|
std::string label = pn;
|
||||||
|
/* don't add the direction currently, a name is sufficient
|
||||||
|
if (! dir.empty ()) {
|
||||||
|
label += ":";
|
||||||
|
label += dir;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
db::properties_id_type prop_id = 0;
|
||||||
|
if (produce_pin_props ()) {
|
||||||
|
db::PropertiesRepository::properties_set props;
|
||||||
|
props.insert (std::make_pair (pin_prop_name_id (), tl::Variant (label)));
|
||||||
|
prop_id = layout.properties_repository ().properties_id (props);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map <std::string, db::Box> bboxes;
|
||||||
|
read_geometries (layout, cell, Pins, &bboxes, prop_id);
|
||||||
|
|
||||||
|
for (std::map <std::string, db::Box>::const_iterator b = bboxes.begin (); b != bboxes.end (); ++b) {
|
||||||
|
std::pair <bool, unsigned int> dl = open_layer (layout, b->first, Label);
|
||||||
|
if (dl.first) {
|
||||||
|
cell.shapes (dl.second).insert (db::Text (label.c_str (), db::Trans (b->second.center () - db::Point ())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expect ("END");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
while (! test (";")) {
|
||||||
|
take ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expect (pn);
|
||||||
|
|
||||||
|
} else if (test ("OBS")) {
|
||||||
|
|
||||||
|
read_geometries (layout, cell, Obstructions);
|
||||||
|
expect ("END");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
while (! test (";")) {
|
||||||
|
take ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair <bool, unsigned int> dl = open_layer (layout, std::string (), Outline);
|
||||||
|
if (dl.first) {
|
||||||
|
cell.shapes (dl.second).insert (db::Box (-origin, -origin + size));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_macro_bboxes_by_name.insert (std::make_pair (mn, db::Box (-origin, -origin + size)));
|
||||||
|
|
||||||
|
reset_cellname ();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LEFImporter::do_read (db::Layout &layout)
|
LEFImporter::do_read (db::Layout &layout)
|
||||||
{
|
{
|
||||||
|
|
@ -414,45 +850,7 @@ LEFImporter::do_read (db::Layout &layout)
|
||||||
|
|
||||||
} else if (test ("NONDEFAULTRULE")) {
|
} else if (test ("NONDEFAULTRULE")) {
|
||||||
|
|
||||||
// read NONDEFAULTRULE sections
|
read_nondefaultrule (layout);
|
||||||
std::string n = get ();
|
|
||||||
|
|
||||||
while (! test ("END") || ! test (n)) {
|
|
||||||
|
|
||||||
if (test ("LAYER")) {
|
|
||||||
|
|
||||||
std::string l = get ();
|
|
||||||
|
|
||||||
// read the width for the layer
|
|
||||||
while (! test ("END")) {
|
|
||||||
if (test ("WIDTH")) {
|
|
||||||
double w = get_double ();
|
|
||||||
test (";");
|
|
||||||
m_nondefault_widths[n][l] = w;
|
|
||||||
} else {
|
|
||||||
while (! test (";")) {
|
|
||||||
take ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
test (l);
|
|
||||||
|
|
||||||
} else if (test ("VIA")) {
|
|
||||||
|
|
||||||
// ignore VIA statements
|
|
||||||
std::string v = get ();
|
|
||||||
while (! test ("END") || ! test (v)) {
|
|
||||||
take ();
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
while (! test (";")) {
|
|
||||||
take ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (test ("SITE")) {
|
} else if (test ("SITE")) {
|
||||||
|
|
||||||
|
|
@ -472,163 +870,7 @@ LEFImporter::do_read (db::Layout &layout)
|
||||||
|
|
||||||
} else if (test ("VIA")) {
|
} else if (test ("VIA")) {
|
||||||
|
|
||||||
std::string n = get ();
|
read_viadef (layout);
|
||||||
|
|
||||||
// produce a cell for vias
|
|
||||||
std::string cellname = "VIA_" + n;
|
|
||||||
db::Cell &cell = layout.cell (layout.add_cell (cellname.c_str ()));
|
|
||||||
|
|
||||||
ViaDesc &via_desc = m_vias[n];
|
|
||||||
via_desc.cell = &cell;
|
|
||||||
|
|
||||||
while (test ("DEFAULT") || test ("TOPOFSTACKONLY"))
|
|
||||||
;
|
|
||||||
test (";");
|
|
||||||
|
|
||||||
if (test ("VIARULE")) {
|
|
||||||
|
|
||||||
db::Vector cutsize, cutspacing;
|
|
||||||
db::Vector be, te;
|
|
||||||
db::Vector bo, to;
|
|
||||||
db::Point offset;
|
|
||||||
int rows = 1, columns = 1;
|
|
||||||
std::string pattern;
|
|
||||||
|
|
||||||
std::vector<std::pair<std::string, std::vector<db::Polygon> > > geometry;
|
|
||||||
geometry.push_back (std::pair<std::string, std::vector<db::Polygon> > ());
|
|
||||||
geometry.push_back (std::pair<std::string, std::vector<db::Polygon> > ());
|
|
||||||
geometry.push_back (std::pair<std::string, std::vector<db::Polygon> > ());
|
|
||||||
|
|
||||||
while (! test ("END")) {
|
|
||||||
|
|
||||||
double x, y;
|
|
||||||
|
|
||||||
if (test ("CUTSIZE")) {
|
|
||||||
|
|
||||||
x = get_double ();
|
|
||||||
y = get_double ();
|
|
||||||
cutsize = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ()));
|
|
||||||
|
|
||||||
test (";");
|
|
||||||
|
|
||||||
} else if (test ("CUTSPACING")) {
|
|
||||||
|
|
||||||
x = get_double ();
|
|
||||||
y = get_double ();
|
|
||||||
cutspacing = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ()));
|
|
||||||
|
|
||||||
test (";");
|
|
||||||
|
|
||||||
} else if (test ("ORIGIN")) {
|
|
||||||
|
|
||||||
x = get_double ();
|
|
||||||
y = get_double ();
|
|
||||||
offset = db::Point (db::DPoint (x / layout.dbu (), y / layout.dbu ()));
|
|
||||||
|
|
||||||
test (";");
|
|
||||||
|
|
||||||
} else if (test ("ENCLOSURE")) {
|
|
||||||
|
|
||||||
x = get_double ();
|
|
||||||
y = get_double ();
|
|
||||||
be = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ()));
|
|
||||||
|
|
||||||
x = get_double ();
|
|
||||||
y = get_double ();
|
|
||||||
te = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ()));
|
|
||||||
|
|
||||||
test (";");
|
|
||||||
|
|
||||||
} else if (test ("OFFSET")) {
|
|
||||||
|
|
||||||
x = get_double ();
|
|
||||||
y = get_double ();
|
|
||||||
bo = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ()));
|
|
||||||
|
|
||||||
x = get_double ();
|
|
||||||
y = get_double ();
|
|
||||||
to = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ()));
|
|
||||||
|
|
||||||
test (";");
|
|
||||||
|
|
||||||
} else if (test ("ROWCOL")) {
|
|
||||||
|
|
||||||
rows = get_long ();
|
|
||||||
columns = get_long ();
|
|
||||||
|
|
||||||
test (";");
|
|
||||||
|
|
||||||
} else if (test ("PATTERN")) {
|
|
||||||
|
|
||||||
pattern = get ();
|
|
||||||
|
|
||||||
test (";");
|
|
||||||
|
|
||||||
} else if (test ("LAYERS")) {
|
|
||||||
|
|
||||||
via_desc.m1 = geometry[0].first = get ();
|
|
||||||
geometry[1].first = get ();
|
|
||||||
via_desc.m2 = geometry[2].first = get ();
|
|
||||||
|
|
||||||
test (";");
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
while (! test (";")) {
|
|
||||||
take ();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
create_generated_via (geometry [0].second, geometry [1].second, geometry [2].second,
|
|
||||||
cutsize, cutspacing, be, te, bo, to, offset, rows, columns, pattern);
|
|
||||||
|
|
||||||
for (std::vector<std::pair<std::string, std::vector<db::Polygon> > >::const_iterator g = geometry.begin (); g != geometry.end (); ++g) {
|
|
||||||
std::pair <bool, unsigned int> dl = open_layer (layout, g->first, ViaGeometry);
|
|
||||||
if (dl.first) {
|
|
||||||
for (std::vector<db::Polygon>::const_iterator p = g->second.begin (); p != g->second.end (); ++p) {
|
|
||||||
cell.shapes (dl.second).insert (*p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// ignore resistance spec
|
|
||||||
if (test ("RESISTANCE")) {
|
|
||||||
get_double ();
|
|
||||||
test (";");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::map<std::string, db::Box> bboxes;
|
|
||||||
read_geometries (layout, cell, ViaGeometry, &bboxes);
|
|
||||||
|
|
||||||
// determine m1 and m2 layers
|
|
||||||
|
|
||||||
std::vector<std::string> routing_layers;
|
|
||||||
for (std::map<std::string, db::Box>::const_iterator b = bboxes.begin (); b != bboxes.end (); ++b) {
|
|
||||||
if (m_routing_layers.find (b->first) != m_routing_layers.end ()) {
|
|
||||||
routing_layers.push_back (b->first);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (routing_layers.size () == 2) {
|
|
||||||
via_desc.m1 = routing_layers[0];
|
|
||||||
via_desc.m2 = routing_layers[1];
|
|
||||||
} else {
|
|
||||||
warn ("Can't determine routing layers for via: " + n);
|
|
||||||
}
|
|
||||||
|
|
||||||
reset_cellname ();
|
|
||||||
|
|
||||||
expect ("END");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
test ("VIA");
|
|
||||||
expect (n);
|
|
||||||
|
|
||||||
} else if (test ("BEGINEXT")) {
|
} else if (test ("BEGINEXT")) {
|
||||||
|
|
||||||
|
|
@ -639,157 +881,11 @@ LEFImporter::do_read (db::Layout &layout)
|
||||||
|
|
||||||
} else if (test ("LAYER")) {
|
} else if (test ("LAYER")) {
|
||||||
|
|
||||||
std::string ln = get ();
|
read_layer (layout);
|
||||||
|
|
||||||
register_layer (ln);
|
|
||||||
|
|
||||||
// just extract the width from the layer - we need that as the default width for paths
|
|
||||||
while (! at_end ()) {
|
|
||||||
if (test ("END")) {
|
|
||||||
expect (ln);
|
|
||||||
break;
|
|
||||||
} else if (test ("TYPE")) {
|
|
||||||
if (test ("ROUTING")) {
|
|
||||||
m_routing_layers.insert (ln);
|
|
||||||
} else if (test ("CUT")) {
|
|
||||||
m_cut_layers.insert (ln);
|
|
||||||
} else {
|
|
||||||
get ();
|
|
||||||
}
|
|
||||||
expect (";");
|
|
||||||
} else if (test ("WIDTH")) {
|
|
||||||
double w = get_double ();
|
|
||||||
m_default_widths.insert (std::make_pair (ln, w));
|
|
||||||
expect (";");
|
|
||||||
} else if (test ("WIREEXTENSION")) {
|
|
||||||
double w = get_double ();
|
|
||||||
m_default_ext.insert (std::make_pair (ln, w));
|
|
||||||
expect (";");
|
|
||||||
} else if (test ("ACCURRENTDENSITY")) {
|
|
||||||
// ACCURRENTDENSITY needs some special attention because it can contain nested WIDTH
|
|
||||||
// blocks following a semicolon
|
|
||||||
take ();
|
|
||||||
if (test ("FREQUENCY")) {
|
|
||||||
while (! test ("TABLEENTRIES")) {
|
|
||||||
take ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (! test (";")) {
|
|
||||||
take ();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
while (! test (";")) {
|
|
||||||
take ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (test ("MACRO")) {
|
} else if (test ("MACRO")) {
|
||||||
|
|
||||||
std::string mn = get ();
|
read_macro (layout);
|
||||||
set_cellname (mn);
|
|
||||||
|
|
||||||
db::Cell &cell = layout.cell (layout.add_cell (mn.c_str ()));
|
|
||||||
|
|
||||||
m_macros_by_name.insert (std::make_pair (mn, &cell));
|
|
||||||
|
|
||||||
db::Point origin;
|
|
||||||
db::Vector size;
|
|
||||||
|
|
||||||
// read the macro
|
|
||||||
while (! at_end ()) {
|
|
||||||
|
|
||||||
if (test ("END")) {
|
|
||||||
expect (mn);
|
|
||||||
break;
|
|
||||||
|
|
||||||
} else if (test ("ORIGIN")) {
|
|
||||||
|
|
||||||
double x = get_double ();
|
|
||||||
double y = get_double ();
|
|
||||||
expect (";");
|
|
||||||
origin = db::Point (db::DPoint (x / layout.dbu (), y / layout.dbu ()));
|
|
||||||
|
|
||||||
} else if (test ("SIZE")) {
|
|
||||||
|
|
||||||
double x = get_double ();
|
|
||||||
test ("BY");
|
|
||||||
double y = get_double ();
|
|
||||||
expect (";");
|
|
||||||
size = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ()));
|
|
||||||
|
|
||||||
} else if (test ("PIN")) {
|
|
||||||
|
|
||||||
std::string pn = get ();
|
|
||||||
std::string dir;
|
|
||||||
|
|
||||||
while (! at_end ()) {
|
|
||||||
if (test ("END")) {
|
|
||||||
break;
|
|
||||||
} else if (test ("DIRECTION")) {
|
|
||||||
dir = get ();
|
|
||||||
test (";");
|
|
||||||
} else if (test ("PORT")) {
|
|
||||||
|
|
||||||
// produce pin labels
|
|
||||||
// TODO: put a label on every single object?
|
|
||||||
std::string label = pn;
|
|
||||||
/* don't add the direction currently, a name is sufficient
|
|
||||||
if (! dir.empty ()) {
|
|
||||||
label += ":";
|
|
||||||
label += dir;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
db::properties_id_type prop_id = 0;
|
|
||||||
if (produce_pin_props ()) {
|
|
||||||
db::PropertiesRepository::properties_set props;
|
|
||||||
props.insert (std::make_pair (pin_prop_name_id (), tl::Variant (label)));
|
|
||||||
prop_id = layout.properties_repository ().properties_id (props);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::map <std::string, db::Box> bboxes;
|
|
||||||
read_geometries (layout, cell, Pins, &bboxes, prop_id);
|
|
||||||
|
|
||||||
for (std::map <std::string, db::Box>::const_iterator b = bboxes.begin (); b != bboxes.end (); ++b) {
|
|
||||||
std::pair <bool, unsigned int> dl = open_layer (layout, b->first, Label);
|
|
||||||
if (dl.first) {
|
|
||||||
cell.shapes (dl.second).insert (db::Text (label.c_str (), db::Trans (b->second.center () - db::Point ())));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
expect ("END");
|
|
||||||
|
|
||||||
} else {
|
|
||||||
while (! test (";")) {
|
|
||||||
take ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
expect (pn);
|
|
||||||
|
|
||||||
} else if (test ("OBS")) {
|
|
||||||
|
|
||||||
read_geometries (layout, cell, Obstructions);
|
|
||||||
expect ("END");
|
|
||||||
|
|
||||||
} else {
|
|
||||||
while (! test (";")) {
|
|
||||||
take ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair <bool, unsigned int> dl = open_layer (layout, std::string (), Outline);
|
|
||||||
if (dl.first) {
|
|
||||||
cell.shapes (dl.second).insert (db::Box (-origin, -origin + size));
|
|
||||||
}
|
|
||||||
|
|
||||||
m_macro_bboxes_by_name.insert (std::make_pair (mn, db::Box (-origin, -origin + size)));
|
|
||||||
|
|
||||||
reset_cellname ();
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
while (! test (";")) {
|
while (! test (";")) {
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,11 @@ public:
|
||||||
*/
|
*/
|
||||||
double layer_ext (const std::string &layer, double def_ext = 0.0) const;
|
double layer_ext (const std::string &layer, double def_ext = 0.0) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the minimum wire width in x and y direction for the given layer name
|
||||||
|
*/
|
||||||
|
std::pair<double, double> min_layer_width (const std::string &layer) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns true if the given layer is a routing layer
|
* @brief Returns true if the given layer is a routing layer
|
||||||
*/
|
*/
|
||||||
|
|
@ -119,6 +124,7 @@ private:
|
||||||
std::map<std::string, std::map<std::string, double> > m_nondefault_widths;
|
std::map<std::string, std::map<std::string, double> > m_nondefault_widths;
|
||||||
std::map<std::string, double> m_default_widths;
|
std::map<std::string, 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, db::Cell *> m_macros_by_name;
|
std::map<std::string, db::Cell *> m_macros_by_name;
|
||||||
std::map<std::string, db::Box> m_macro_bboxes_by_name;
|
std::map<std::string, db::Box> m_macro_bboxes_by_name;
|
||||||
std::map<std::string, ViaDesc> m_vias;
|
std::map<std::string, ViaDesc> m_vias;
|
||||||
|
|
@ -126,6 +132,12 @@ private:
|
||||||
|
|
||||||
std::vector <db::Trans> get_iteration (db::Layout &layout);
|
std::vector <db::Trans> get_iteration (db::Layout &layout);
|
||||||
void read_geometries (db::Layout &layout, db::Cell &cell, LayerPurpose purpose, std::map<std::string, db::Box> *collect_bboxes = 0, properties_id_type prop_id = 0);
|
void read_geometries (db::Layout &layout, db::Cell &cell, LayerPurpose purpose, std::map<std::string, db::Box> *collect_bboxes = 0, properties_id_type prop_id = 0);
|
||||||
|
void read_nondefaultrule (Layout &layout);
|
||||||
|
void read_viadef (Layout &layout);
|
||||||
|
void read_viadef_by_rule (Layout &layout, db::Cell &cell, ViaDesc &desc, const std::string &n);
|
||||||
|
void read_viadef_by_geometry (Layout &layout, db::Cell &cell, ViaDesc &desc, const std::string &n);
|
||||||
|
void read_layer (Layout &layout);
|
||||||
|
void read_macro (Layout &layout);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -270,12 +270,17 @@ TEST(103)
|
||||||
run_test (_this, "issue-517", "def:in.def", "au.oas.gz", default_options (), false);
|
run_test (_this, "issue-517", "def:in.def", "au.oas.gz", default_options (), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(104)
|
TEST(104_doxy_vias)
|
||||||
{
|
{
|
||||||
run_test (_this, "doxy_vias", "def:test.def", "au.oas.gz", default_options (), false);
|
run_test (_this, "doxy_vias", "def:test.def", "au.oas.gz", default_options (), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(105)
|
TEST(105_specialnets_geo)
|
||||||
{
|
{
|
||||||
run_test (_this, "specialnets_geo", "lef:test.lef+def:test.def", "au.oas.gz", default_options (), false);
|
run_test (_this, "specialnets_geo", "lef:test.lef+def:test.def", "au.oas.gz", default_options (), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(106_wrongdirection)
|
||||||
|
{
|
||||||
|
run_test (_this, "wrongdirection", "lef:test.lef+def:test.def", "au.oas.gz", default_options (), false);
|
||||||
|
}
|
||||||
|
|
|
||||||
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 0 ) ( 2000 0 ) via34 ( * 2000 ) ( 4000 * ) ( * 4000 )
|
||||||
|
;
|
||||||
|
END NETS
|
||||||
|
END DESIGN
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
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.6 ;
|
||||||
|
END M3
|
||||||
|
|
||||||
|
LAYER VIA3
|
||||||
|
TYPE CUT ;
|
||||||
|
END VIA3
|
||||||
|
|
||||||
|
LAYER M4
|
||||||
|
TYPE ROUTING ;
|
||||||
|
DIRECTION HORIZONTAL ;
|
||||||
|
WIDTH 0.5 ;
|
||||||
|
PROPERTY LEF58_MINWIDTH "MINWIDTH 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