Tried to implement MINWIDTH .. WRONGDIRECTION in LEF58_MINWIDTH property

This commit is contained in:
Matthias Koefferlein 2020-04-04 00:40:01 +02:00
parent bcaf28c94c
commit 4a24b727d5
10 changed files with 623 additions and 367 deletions

View File

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

View File

@ -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);
}; };
} }

View File

@ -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 ()) {

View File

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

View File

@ -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 (";")) {

View File

@ -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);
}; };
} }

View File

@ -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);
}

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

Binary file not shown.

19
testdata/lefdef/wrongdirection/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 0 ) ( 2000 0 ) via34 ( * 2000 ) ( 4000 * ) ( * 4000 )
;
END NETS
END DESIGN

41
testdata/lefdef/wrongdirection/test.lef vendored Normal file
View File

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