diff --git a/src/buddies/src/bd/strmxor.cc b/src/buddies/src/bd/strmxor.cc index 211cef593..030677066 100644 --- a/src/buddies/src/bd/strmxor.cc +++ b/src/buddies/src/bd/strmxor.cc @@ -140,7 +140,7 @@ struct XORData double tile_size; db::Layout *output_layout; db::cell_index_type output_cell; - std::map > l2l_map; + std::map, db::LPLogicalLessFunc> l2l_map; std::map, ResultDescriptor> *results; }; @@ -299,7 +299,7 @@ BD_PUBLIC int strmxor (int argc, char *argv[]) throw tl::Exception ("'" + top_b + "' is not a valid cell name in second layout"); } - std::map > l2l_map; + std::map, db::LPLogicalLessFunc> l2l_map; for (db::Layout::layer_iterator l = layout_a.begin_layers (); l != layout_a.end_layers (); ++l) { l2l_map.insert (std::make_pair (*(*l).second, std::make_pair (-1, -1))).first->second.first = (*l).first; diff --git a/src/db/db/dbLayoutUtils.h b/src/db/db/dbLayoutUtils.h index 07ba86332..badbf8ae6 100644 --- a/src/db/db/dbLayoutUtils.h +++ b/src/db/db/dbLayoutUtils.h @@ -42,7 +42,7 @@ namespace db * * This implementation will create new layers if required. */ -class DirectLayerMapping +class DB_PUBLIC DirectLayerMapping : public ImportLayerMapping { public: diff --git a/src/db/db/dbReader.cc b/src/db/db/dbReader.cc index 4e1455bc1..fc6f13adb 100644 --- a/src/db/db/dbReader.cc +++ b/src/db/db/dbReader.cc @@ -24,6 +24,8 @@ #include "dbReader.h" #include "dbStream.h" #include "tlClassRegistry.h" +#include "tlTimer.h" +#include "tlLog.h" namespace db { @@ -74,5 +76,21 @@ Reader::~Reader () } } +const db::LayerMap & +Reader::read (db::Layout &layout, const db::LoadLayoutOptions &options) +{ + tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Reading file: ")) + m_stream.source ()); + + return mp_actual_reader->read (layout, options); +} + +const db::LayerMap & +Reader::read (db::Layout &layout) +{ + tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Reading file: ")) + m_stream.source ()); + + return mp_actual_reader->read (layout); +} + } diff --git a/src/db/db/dbReader.h b/src/db/db/dbReader.h index 6429ea71b..bab39df87 100644 --- a/src/db/db/dbReader.h +++ b/src/db/db/dbReader.h @@ -125,10 +125,7 @@ public: * @param layout The layout object to write to * @param options The LayerMap object */ - const db::LayerMap &read (db::Layout &layout, const db::LoadLayoutOptions &options) - { - return mp_actual_reader->read (layout, options); - } + const db::LayerMap &read (db::Layout &layout, const db::LoadLayoutOptions &options); /** * @brief The basic read method (without mapping) @@ -143,10 +140,7 @@ public: * @param layout The layout object to write to * @return The LayerMap object */ - const db::LayerMap &read (db::Layout &layout) - { - return mp_actual_reader->read (layout); - } + const db::LayerMap &read (db::Layout &layout); /** * @brief Returns a format describing the file format found diff --git a/src/db/db/dbWriter.cc b/src/db/db/dbWriter.cc index 5dfdcefa0..917790212 100644 --- a/src/db/db/dbWriter.cc +++ b/src/db/db/dbWriter.cc @@ -26,6 +26,8 @@ #include "tlClassRegistry.h" #include "tlAssert.h" #include "tlStream.h" +#include "tlTimer.h" +#include "tlLog.h" namespace db { @@ -54,6 +56,8 @@ Writer::~Writer () void Writer::write (db::Layout &layout, tl::OutputStream &stream) { + tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Writing file: ")) + stream.path ()); + tl_assert (mp_writer != 0); mp_writer->write (layout, stream, m_options); } diff --git a/src/laybasic/laybasic/layLayerProperties.cc b/src/laybasic/laybasic/layLayerProperties.cc index 53a4e88be..e150fa401 100644 --- a/src/laybasic/laybasic/layLayerProperties.cc +++ b/src/laybasic/laybasic/layLayerProperties.cc @@ -1839,10 +1839,15 @@ LayerPropertiesList::load (tl::XMLSource &stream, std::vector = 21, tl::to_string (tr ("File read: ")) + m_stream.source ()); - try { double sf = 0.01 / m_dbu; diff --git a/src/plugins/streamers/dxf/db_plugin/dbDXFReader.cc b/src/plugins/streamers/dxf/db_plugin/dbDXFReader.cc index 3874e4026..cb023d887 100644 --- a/src/plugins/streamers/dxf/db_plugin/dbDXFReader.cc +++ b/src/plugins/streamers/dxf/db_plugin/dbDXFReader.cc @@ -379,8 +379,6 @@ DXFReader::open_layer (db::Layout &layout, const std::string &n) void DXFReader::do_read (db::Layout &layout, db::cell_index_type top) { - tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("File read: ")) + m_stream.source ()); - // create the zero layer - this is not mapped to GDS but can be specified in the layer mapping as // a layer named "0". std::pair ll = layer_map ().logical (zero_layer_name, layout); diff --git a/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc b/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc index e3d8d45a0..1541960e0 100644 --- a/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc +++ b/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc @@ -233,8 +233,6 @@ eq_y (const GDS2XY &a, const GDS2XY &b) void GDS2ReaderBase::do_read (db::Layout &layout) { - tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("File read: ")) + path ()); - m_cellname = ""; m_libname = ""; m_mapped_cellnames.clear (); diff --git a/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc index 5ee27d495..87c25cfe2 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc @@ -30,6 +30,28 @@ namespace db { +struct DEFImporterGroup +{ + DEFImporterGroup (const std::string &n, const std::string &rn, const std::vector &m) + : name (n), region_name (rn), comp_match (m) + { + // .. nothing yet .. + } + + bool comp_matches (const std::string &name) const + { + for (std::vector::const_iterator m = comp_match.begin (); m != comp_match.end (); ++m) { + if (m->match (name)) { + return true; + } + } + return false; + } + + std::string name, region_name; + std::vector comp_match; +}; + DEFImporter::DEFImporter () : LEFDEFImporter () { @@ -37,39 +59,12 @@ DEFImporter::DEFImporter () } void -DEFImporter::read_lef (tl::InputStream &stream, db::Layout &layout, LEFDEFLayerDelegate &ld) +DEFImporter::read_lef (tl::InputStream &stream, db::Layout &layout, LEFDEFReaderState &state) { - m_lef_importer.read (stream, layout, ld); + m_lef_importer.read (stream, layout, state); } -db::FTrans -DEFImporter::get_orient (bool optional) -{ - if (test ("N")) { - return db::FTrans (db::FTrans::r0); - } else if (test ("S")) { - return db::FTrans (db::FTrans::r180); - } else if (test ("W")) { - return db::FTrans (db::FTrans::r90); - } else if (test ("E")) { - return db::FTrans (db::FTrans::r270); - } else if (test ("FN")) { - return db::FTrans (db::FTrans::m90); - } else if (test ("FS")) { - return db::FTrans (db::FTrans::m0); - } else if (test ("FW")) { - return db::FTrans (db::FTrans::m45); - } else if (test ("FE")) { - return db::FTrans (db::FTrans::m135); - } else if (optional) { - return db::FTrans (db::FTrans::r0); - } else { - error (tl::to_string (tr ("Invalid orientation specification: ")) + get ()); - return db::FTrans (db::FTrans::r0); - } -} - void DEFImporter::read_polygon (db::Polygon &poly, double scale) { @@ -97,56 +92,1105 @@ DEFImporter::read_polygon (db::Polygon &poly, double scale) void DEFImporter::read_rect (db::Polygon &poly, double scale) { - double x = 0.0, y = 0.0; - test ("("); - x = get_double (); - y = get_double (); - db::Point pt1 = db::Point (db::DPoint (x * scale, y * scale)); + db::Point pt1 = get_point (scale); test (")"); test ("("); - x = get_double (); - y = get_double (); - db::Point pt2 = db::Point (db::DPoint (x * scale, y * scale)); + db::Point pt2 = get_point (scale); test (")"); poly = db::Polygon (db::Box (pt1, pt2)); } -struct Group +std::pair +DEFImporter::get_wire_width_for_rule (const std::string &rulename, const std::string &ln, double dbu) { - Group (const std::string &n, const std::string &rn, const std::vector &m) - : name (n), region_name (rn), comp_match (m) - { - // .. nothing yet .. - } + std::pair wxy = m_lef_importer.layer_width (ln, rulename); + db::Coord wx = db::coord_traits::rounded (wxy.first / dbu); + db::Coord wy = db::coord_traits::rounded (wxy.second / dbu); - bool comp_matches (const std::string &name) const - { - for (std::vector::const_iterator m = comp_match.begin (); m != comp_match.end (); ++m) { - if (m->match (name)) { - return true; + // try to find local nondefault rule + if (! rulename.empty ()) { + std::map >::const_iterator nd = m_nondefault_widths.find (rulename); + if (nd != m_nondefault_widths.end ()) { + std::map::const_iterator ld = nd->second.find (ln); + if (ld != nd->second.end ()) { + wx = wy = ld->second; } } - return false; } - std::string name, region_name; - std::vector comp_match; -}; + std::pair min_wxy = m_lef_importer.min_layer_width (ln); + db::Coord min_wx = db::coord_traits::rounded (min_wxy.first / dbu); + db::Coord min_wy = db::coord_traits::rounded (min_wxy.second / dbu); + + return std::make_pair (std::max (wx, min_wx), std::max (wy, min_wy)); +} + +std::pair +DEFImporter::get_def_ext (const std::string &ln, const std::pair &wxy, double dbu) +{ + // 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::rounded (m_lef_importer.layer_ext (ln, std::min (wxy.first, wxy.second) * 0.5 * dbu) / dbu); + return std::make_pair (de, de); +} + +void +DEFImporter::read_diearea (db::Layout &layout, db::Cell &design, double scale) +{ + std::vector points; + + while (! test (";")) { + test ("("); + points.push_back (get_point (scale)); + test (")"); + } + + if (points.size () >= 2) { + + // create outline shape + std::pair dl = open_layer (layout, std::string (), Outline); + if (dl.first) { + if (points.size () == 2) { + design.shapes (dl.second).insert (db::Box (points [0], points [1])); + } else { + db::Polygon p; + p.assign_hull (points.begin (), points.end ()); + design.shapes (dl.second).insert (p); + } + } + + } +} + +void +DEFImporter::read_nondefaultrules (double scale) +{ + 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::rounded (w); + } + + } + + // parse over the rest + while (! peek ("+") && ! peek ("-") && ! peek (";")) { + take (); + } + + } + + test (";"); + + } +} + +void +DEFImporter::read_regions (std::map > ®ions, double scale) +{ + while (test ("-")) { + + std::string n = get (); + std::vector &polygons = regions [n]; + + while (! peek (";")) { + + if (test ("+")) { + + // ignore other options for now + while (! peek (";")) { + take (); + } + break; + + } else { + + db::Polygon box; + read_rect (box, scale); + polygons.push_back (box); + + } + + } + + test (";"); + + } +} +void +DEFImporter::read_groups (std::list &groups, double /*scale*/) +{ + while (test ("-")) { + + std::string n = get (); + std::string rn; + std::vector match; + + while (! peek (";")) { + + if (test ("+")) { + + // gets the region name if there is one + if (test ("REGION")) { + rn = get (); + } + + // ignore the reset for now + while (! peek (";")) { + take (); + } + break; + + } else { + + match.push_back (tl::GlobPattern (get ())); + + } + + } + + groups.push_back (DEFImporterGroup (n, rn, match)); + + test (";"); + + } +} + +void +DEFImporter::read_blockages (db::Layout &layout, db::Cell &design, double scale) +{ + while (test ("-")) { + + std::string layer; + + while (! test (";")) { + + if (test ("PLACEMENT")) { + + // indicates a placement blockage + layer = std::string (); + + } else if (test ("LAYER")) { + + layer = get (); + + } else if (test ("+")) { + + // ignore options for now + while (! peek ("RECT") && ! peek ("POLYGON") && ! peek ("+") && ! peek ("-") && ! peek (";")) { + take (); + } + + } else if (test ("POLYGON")) { + + db::Polygon p; + read_polygon (p, scale); + + std::pair dl = open_layer (layout, layer, layer.empty () ? PlacementBlockage : Blockage); + if (dl.first) { + design.shapes (dl.second).insert (p); + } + + } else if (test ("RECT")) { + + db::Polygon p; + read_rect (p, scale); + + std::pair dl = open_layer (layout, layer, layer.empty () ? PlacementBlockage : Blockage); + if (dl.first) { + design.shapes (dl.second).insert (p); + } + + } else { + expect (";"); + } + + } + + } +} + +void +DEFImporter::produce_routing_geometry (db::Cell &design, const Polygon *style, unsigned int layer, properties_id_type prop_id, const std::vector &pts, const std::vector > &ext, std::pair w) +{ + if (! style) { + + // Use the default style (octagon "pen" for non-manhattan segments, paths for + // horizontal/vertical segments). + // Manhattan paths are stitched together from two-point paths if the + // horizontal and vertical width is different. + + bool is_isotropic = (w.first == w.second); + bool was_path_before = false; + + std::vector::const_iterator pt = pts.begin (); + while (pt != pts.end ()) { + + std::vector::const_iterator pt0 = pt; + ++pt; + if (pt == pts.end ()) { + break; + } + + bool multipart = false; + if (is_isotropic) { + while (pt != pts.end () && (pt[-1].x () == pt[0].x () || pt[-1].y () == pt[0].y())) { + ++pt; + multipart = true; + } + if (multipart) { + --pt; + } + } + + // The next part is the interval [pt0..pt] (pt inclusive) + + if (multipart || (pt0->x () == pt0[1].x () || pt0->y () == pt0[1].y())) { + + db::Coord wxy, wxy_perp; + + if (pt0->x () == pt0 [1].x ()) { + wxy = w.second; + wxy_perp = w.first; + } else { + wxy = w.first; + wxy_perp = w.second; + } + + // compute begin extension + db::Coord be = 0; + if (pt0 == pts.begin ()) { + be = ext.front ().first; + } else if (was_path_before) { + // provides the overlap to the previous segment + be = wxy_perp / 2; + } + + // compute end extension + db::Coord ee = 0; + if (pt + 1 == pts.end ()) { + ee = ext.back ().first; + } + + db::Path p (pt0, pt + 1, wxy, be, ee, false); + if (prop_id != 0) { + design.shapes (layer).insert (db::object_with_properties (p, prop_id)); + } else { + design.shapes (layer).insert (p); + } + + was_path_before = true; + + } else { + + 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 (-s, t), + db::Point (-t, s), + db::Point (t, s), + db::Point (s, t), + db::Point (s, -t), + db::Point (t, -s), + db::Point (-t, -s), + db::Point (-s, -t) + }; + + db::Polygon k; + k.assign_hull (octagon, octagon + sizeof (octagon) / sizeof (octagon[0])); + + db::Polygon p = db::minkowsky_sum (k, db::Edge (*pt0, *pt)); + if (prop_id != 0) { + design.shapes (layer).insert (db::object_with_properties (p, prop_id)); + } else { + design.shapes (layer).insert (p); + } + + was_path_before = false; + + } + + } + + } else { + + for (size_t i = 0; i < pts.size () - 1; ++i) { + db::Polygon p = db::minkowsky_sum (*style, db::Edge (pts [i], pts [i + 1])); + if (prop_id != 0) { + design.shapes (layer).insert (db::object_with_properties (p, prop_id)); + } else { + design.shapes (layer).insert (p); + } + } + + } +} + +void +DEFImporter::read_single_net (std::string &nondefaultrule, Layout &layout, db::Cell &design, double scale, db::properties_id_type prop_id, bool specialnets) +{ + std::string taperrule; + + do { + + std::string ln = get (); + + taperrule.clear (); + const std::string *rulename = 0; + + std::pair w (0, 0); + if (specialnets) { + db::Coord n = db::coord_traits::rounded (get_double () * scale); + w = std::make_pair (n, n); + } + + const db::Polygon *style = 0; + + int sn = std::numeric_limits::max (); + + if (specialnets) { + + while (test ("+")) { + + if (test ("STYLE")) { + sn = get_long (); + } else if (test ("SHAPE")) { + take (); + } + + } + + } else { + + while (true) { + if (test ("TAPER")) { + taperrule.clear (); + rulename = &taperrule; + } else if (test ("TAPERRULE")) { + taperrule = get (); + rulename = &taperrule; + } else if (test ("STYLE")) { + sn = get_long (); + } else { + break; + } + } + + } + + if (! rulename) { + rulename = &nondefaultrule; + } + + std::pair def_ext (0, 0); + + if (! specialnets) { + w = get_wire_width_for_rule (*rulename, ln, layout.dbu ()); + def_ext = get_def_ext (ln, w, layout.dbu ()); + } + + std::map::const_iterator s = m_styles.find (sn); + if (s != m_styles.end ()) { + style = &s->second; + } + + std::vector > ext; + std::vector pts; + + double x = 0.0, y = 0.0; + + while (true) { + + if (test ("MASK")) { + // ignore mask spec + get_long (); + } + + if (test ("RECT")) { + + if (! test ("(")) { + error (tl::to_string (tr ("RECT routing specification not followed by coordinate list"))); + } + + // breaks wiring + pts.clear (); + + // rect spec + + double x1 = get_double (); + double y1 = get_double (); + double x2 = get_double (); + double y2 = get_double (); + + test (")"); + + std::pair dl = open_layer (layout, ln, specialnets ? SpecialRouting : Routing); + if (dl.first) { + + db::Point p (x, y); + db::Box rect (db::Point (db::DPoint ((x + x1) * scale, (y + y1) * scale)), + db::Point (db::DPoint ((x + x2) * scale, (y + y2) * scale))); + + if (prop_id != 0) { + design.shapes (dl.second).insert (db::object_with_properties (rect, prop_id)); + } else { + design.shapes (dl.second).insert (rect); + } + + } + + } else if (test ("VIRTUAL")) { + + // virtual specs simply create a new segment + pts.clear (); + + } else if (peek ("(")) { + + while (peek ("(") || peek ("MASK")) { + + if (test ("MASK")) { + // ignore MASK spec + get_long (); + } + + if (! test ("(")) { + // We could have a via here: in that case we have swallowed MASK already, but + // since we don't do anything with that, this does not hurt for now. + break; + } + + if (! test ("*")) { + x = get_double (); + } + if (! test ("*")) { + y = get_double (); + } + pts.push_back (db::Point (db::DPoint (x * scale, y * scale))); + std::pair ee = def_ext; + if (! peek (")")) { + db::Coord e = db::coord_traits::rounded (get_double () * scale); + ee.first = ee.second = e; + } + ext.push_back (ee); + + test (")"); + + } + + if (pts.size () > 1) { + std::pair dl = open_layer (layout, ln, specialnets ? SpecialRouting : Routing); + if (dl.first) { + produce_routing_geometry (design, style, dl.second, prop_id, pts, ext, w); + } + } + + } else if (! peek ("NEW") && ! peek ("+") && ! peek ("-") && ! peek (";")) { + + // indicates a via + std::string vn = get (); + db::FTrans ft = get_orient (true /*optional*/); + + db::Coord dx = 0, dy = 0; + long nx = 1, ny = 1; + + if (specialnets && test ("DO")) { + + nx = std::max (0l, get_long ()); + test ("BY"); + ny = std::max (0l, get_long ()); + test ("STEP"); + dx = db::coord_traits::rounded (get_double () * scale); + dy = db::coord_traits::rounded (get_double () * scale); + + if (nx < 0) { + dx = -dx; + nx = -nx; + } + if (ny < 0) { + dy = -dy; + ny = -ny; + } + + } + + std::map::const_iterator vd = m_via_desc.find (vn); + if (vd != m_via_desc.end () && ! pts.empty ()) { + if (nx <= 1 && ny <= 1) { + design.insert (db::CellInstArray (db::CellInst (vd->second.cell->cell_index ()), db::Trans (ft.rot (), db::Vector (pts.back ())))); + } else { + design.insert (db::CellInstArray (db::CellInst (vd->second.cell->cell_index ()), db::Trans (ft.rot (), db::Vector (pts.back ())), db::Vector (dx, 0), db::Vector (0, dy), (unsigned long) nx, (unsigned long) ny)); + } + if (ln == vd->second.m1) { + ln = vd->second.m2; + } else if (ln == vd->second.m2) { + ln = vd->second.m1; + } + } + + if (! specialnets) { + w = get_wire_width_for_rule (*rulename, ln, layout.dbu ()); + def_ext = get_def_ext (ln, w, layout.dbu ()); + } + + // continue a segment with the current point and the new layer + if (pts.size () > 1) { + pts.erase (pts.begin (), pts.end () - 1); + } + + ext.clear (); + ext.push_back (def_ext); + + } else { + break; + } + + } + + } while (test ("NEW")); +} + +void +DEFImporter::read_nets (db::Layout &layout, db::Cell &design, double scale, bool specialnets) +{ + while (test ("-")) { + + std::string net = get (); + std::string nondefaultrule; + std::string stored_netname, stored_nondefaultrule; + db::properties_id_type stored_prop_id; + bool in_subnet = false; + + db::properties_id_type prop_id = 0; + if (produce_net_props ()) { + db::PropertiesRepository::properties_set props; + props.insert (std::make_pair (net_prop_name_id (), tl::Variant (net))); + prop_id = layout.properties_repository ().properties_id (props); + } + + while (test ("(")) { + while (! test (")")) { + take (); + } + } + + while (test ("+")) { + + bool was_shield = false; + + if (! specialnets && test ("SUBNET")) { + + std::string subnetname = get (); + + while (test ("(")) { + while (! test (")")) { + take (); + } + } + + if (! in_subnet) { + stored_netname = net; + stored_nondefaultrule = nondefaultrule; + stored_prop_id = prop_id; + in_subnet = true; + } else { + warn ("Nested subnets"); + } + + net = stored_netname + "/" + subnetname; + + if (produce_net_props ()) { + db::PropertiesRepository::properties_set props; + props.insert (std::make_pair (net_prop_name_id (), tl::Variant (net))); + prop_id = layout.properties_repository ().properties_id (props); + } + + } else if (! specialnets && test ("NONDEFAULTRULE")) { + + nondefaultrule = get (); + + } else { + + bool prefixed = false; + bool can_have_rect_or_polygon = true; + + if ((was_shield = test ("SHIELD")) == true || test ("NOSHIELD") || test ("ROUTED") || test ("FIXED") || test ("COVER")) { + if (was_shield) { + take (); + } + prefixed = true; + can_have_rect_or_polygon = test ("+"); + } + + bool any = false; + + if (can_have_rect_or_polygon && test ("POLYGON")) { + + std::string ln = get (); + + db::Polygon p; + read_polygon (p, scale); + + std::pair dl = open_layer (layout, ln, specialnets ? SpecialRouting : Routing); + if (dl.first) { + if (prop_id != 0) { + design.shapes (dl.second).insert (db::object_with_properties (p, prop_id)); + } else { + design.shapes (dl.second).insert (p); + } + } + + any = true; + + } else if (can_have_rect_or_polygon && test ("RECT")) { + + std::string ln = get (); + + db::Polygon p; + read_rect (p, scale); + + std::pair dl = open_layer (layout, ln, specialnets ? SpecialRouting : Routing); + if (dl.first) { + if (prop_id != 0) { + design.shapes (dl.second).insert (db::object_with_properties (p, prop_id)); + } else { + design.shapes (dl.second).insert (p); + } + } + + any = true; + + } else if (prefixed) { + + read_single_net (nondefaultrule, layout, design, scale, prop_id, specialnets); + any = true; + + } else { + + // lazily skip everything else + while (! peek ("+") && ! peek ("-") && ! peek (";")) { + take (); + } + + } + + if (any && in_subnet) { + + in_subnet = false; + + net = stored_netname; + nondefaultrule = stored_nondefaultrule; + prop_id = stored_prop_id; + + stored_netname.clear (); + stored_nondefaultrule.clear (); + stored_prop_id = 0; + + } + + } + + } + + expect (";"); + + } +} + +void +DEFImporter::read_vias (db::Layout &layout, db::Cell & /*design*/, double scale) +{ + while (test ("-")) { + + std::string n = get (); + ViaDesc &vd = m_via_desc.insert (std::make_pair (n, ViaDesc ())).first->second; + + // produce a cell for vias + std::string cellname = options ().via_cellname_prefix () + n; + db::Cell &cell = layout.cell (layout.add_cell (cellname.c_str ())); + reader_state ()->register_via_cell (n, &cell); + vd.cell = &cell; + + bool has_via_rule = false; + + db::Vector cutsize, cutspacing; + db::Vector be, te; + db::Vector bo, to; + db::Point offset; + int rows = 1, columns = 1; + std::string pattern; + + std::map > geometry; + std::vector *top = 0, *cut = 0, *bottom = 0; + + while (test ("+")) { + + if (test ("VIARULE")) { + + has_via_rule = true; + take (); + + } else if (test ("CUTSIZE")) { + + cutsize = get_vector (scale); + + } else if (test ("CUTSPACING")) { + + cutspacing = get_vector (scale); + + } else if (test ("ORIGIN")) { + + offset = get_point (scale); + + } else if (test ("ENCLOSURE")) { + + be = get_vector (scale); + te = get_vector (scale); + + } else if (test ("OFFSET")) { + + bo = get_vector (scale); + to = get_vector (scale); + + } else if (test ("ROWCOL")) { + + rows = get_long (); + columns = get_long (); + + } else if (test ("PATTERN")) { + + pattern = get (); + + } else if (test ("LAYERS")) { + + std::string bn = get (); + std::string cn = get (); + std::string tn = get (); + + bottom = &geometry.insert (std::make_pair (bn, std::vector ())).first->second; + cut = &geometry.insert (std::make_pair (cn, std::vector ())).first->second; + top = &geometry.insert (std::make_pair (tn, std::vector ())).first->second; + + vd.m1 = bn; + vd.m2 = tn; + + } else if (test ("POLYGON")) { + + std::string ln = get (); + + if (test ("+")) { + expect ("MASK"); + get_long (); + } + + std::vector &polygons = geometry.insert (std::make_pair (ln, std::vector ())).first->second; + polygons.push_back (db::Polygon ()); + read_polygon (polygons.back (), scale); + + } else if (test ("RECT")) { + + std::string ln = get (); + + if (test ("+")) { + expect ("MASK"); + get_long (); + } + + std::vector &polygons = geometry.insert (std::make_pair (ln, std::vector ())).first->second; + polygons.push_back (db::Polygon ()); + read_rect (polygons.back (), scale); + + } + + } + + if (vd.m1.empty () && vd.m2.empty ()) { + + // analyze the layers to find the metals + std::vector routing_layers; + for (std::map >::const_iterator b = geometry.begin (); b != geometry.end (); ++b) { + if (m_lef_importer.is_routing_layer (b->first)) { + routing_layers.push_back (b->first); + } + } + + if (routing_layers.size () == 2) { + vd.m1 = routing_layers[0]; + vd.m2 = routing_layers[1]; + } else { + warn ("Can't determine routing layers for via: " + n); + } + + } + + test (";"); + + if (has_via_rule && top && cut && bottom) { + create_generated_via (*bottom, *cut, *top, + cutsize, cutspacing, be, te, bo, to, offset, rows, columns, pattern); + } + + for (std::map >::const_iterator g = geometry.begin (); g != geometry.end (); ++g) { + std::pair dl = open_layer (layout, g->first, ViaGeometry); + if (dl.first) { + for (std::vector::const_iterator p = g->second.begin (); p != g->second.end (); ++p) { + cell.shapes (dl.second).insert (*p); + } + } + } + + } +} + +void +DEFImporter::read_pins (db::Layout &layout, db::Cell &design, double scale) +{ + while (test ("-")) { + + take (); // pin name + + std::string net; + std::string dir; + std::map > geometry; + db::Trans trans; + + while (test ("+")) { + + bool flush = false; + + if (test ("DIRECTION")) { + dir = get (); + } else if (test ("NET")) { + net = get (); + } else if (test ("LAYER")) { + + std::string ln = get (); + + while (test ("DESIGNRULEWIDTH") || test ("SPACING")) { + take (); + } + + test ("("); + db::Point pt1 = get_point (scale); + test (")"); + + test ("("); + db::Point pt2 = get_point (scale); + test (")"); + + geometry.insert (std::make_pair (ln, std::vector ())).first->second.push_back (db::Polygon (db::Box (pt1, pt2))); + + } else if (test ("POLYGON")) { + + std::string ln = get (); + + while (test ("DESIGNRULEWIDTH") || test ("SPACING")) { + take (); + } + + std::vector points; + + double x = 0.0, y = 0.0; + + while (! test ("+") && ! test (";")) { + + test ("("); + if (! test ("*")) { + x = get_double (); + } + if (! test ("*")) { + y = get_double (); + } + points.push_back (db::Point (db::DPoint (x * scale, y * scale))); + test (")"); + + } + + std::vector &polygons = geometry.insert (std::make_pair (ln, std::vector ())).first->second; + polygons.push_back (db::Polygon ()); + polygons.back ().assign_hull (points.begin (), points.end ()); + + } else if (test ("PLACED") || test ("FIXED") || test ("COVER")) { + + test ("("); + db::Vector d = get_vector (scale); + test (")"); + + db::FTrans ft = get_orient (false /*mandatory*/); + trans = db::Trans (ft.rot (), d); + + } else if (test ("PORT")) { + + flush = true; + + } else { + while (! peek ("+") && ! peek ("-") && ! peek (";")) { + take (); + } + } + + if (flush || ! peek ("+")) { + + // TODO: put a label on every single object? + std::string label = net; + /* don't add the direction currently, a name is sufficient + if (! dir.empty ()) { + label += ":"; + label += dir; + } + */ + + // Produce geometry collected so far + for (std::map >::const_iterator g = geometry.begin (); g != geometry.end (); ++g) { + + std::pair dl = open_layer (layout, g->first, Pins); + if (dl.first) { + + 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); + } + + for (std::vector::const_iterator p = g->second.begin (); p != g->second.end (); ++p) { + db::Polygon pt = p->transformed (trans); + if (prop_id == 0) { + design.shapes (dl.second).insert (pt); + } else { + design.shapes (dl.second).insert (db::PolygonWithProperties (pt, prop_id)); + } + } + + } + + dl = open_layer (layout, g->first, Label); + if (dl.first) { + db::Box bbox; + if (! g->second.empty ()) { + bbox = g->second.back ().box ().transformed (trans); + } + design.shapes (dl.second).insert (db::Text (label.c_str (), db::Trans (db::Vector (bbox.center ())))); + } + + } + + geometry.clear (); + trans = db::Trans (); + + } + + } + + expect (";"); + + } +} + +void +DEFImporter::read_styles (double scale) +{ + while (test ("-")) { + + test ("STYLE"); + + int sn = get_long (); + + std::vector points; + + double x = 0.0, y = 0.0; + + while (! test (";")) { + + test ("("); + if (! test ("*")) { + x = get_double (); + } + if (! test ("*")) { + y = get_double (); + } + points.push_back (db::Point (db::DPoint (x * scale, y * scale))); + test (")"); + + } + + m_styles.insert (std::make_pair (sn, db::Polygon ())).first->second.assign_hull (points.begin (), points.end ()); + + } +} + +void +DEFImporter::read_components (std::list > &instances, double scale) +{ + while (test ("-")) { + + std::string inst_name = get (); + std::string model = get (); + + std::pair ct = m_lef_importer.macro_by_name (model); + + while (test ("+")) { + + if (test ("PLACED") || test ("FIXED") || test ("COVER")) { + + test ("("); + db::Point pt = get_point (scale); + test (")"); + + db::FTrans ft = get_orient (false /*mandatory*/); + db::Vector d = pt - m_lef_importer.macro_bbox_by_name (model).transformed (ft).lower_left (); + + if (ct.first) { + db::CellInstArray inst (db::CellInst (ct.first->cell_index ()), db::Trans (ft.rot (), d) * ct.second); + instances.push_back (std::make_pair (inst_name, inst)); + } else { + warn (tl::to_string (tr ("Macro not found in LEF file: ")) + model); + } + + } else { + while (! peek ("+") && ! peek ("-") && ! peek (";")) { + take (); + } + } + + } + + expect (";"); + + } +} void DEFImporter::do_read (db::Layout &layout) { double dbu_mic = 1000.0; double scale = 1.0 / (dbu_mic * layout.dbu ()); - std::map styles; - std::map via_desc = m_lef_importer.vias (); + std::map > regions; - std::list groups; + std::list groups; std::list > instances; + m_via_desc = m_lef_importer.vias (); + m_styles.clear (); + db::Cell &design = layout.cell (layout.add_cell ("TOP")); while (! at_end ()) { @@ -185,31 +1229,7 @@ DEFImporter::do_read (db::Layout &layout) } else if (test ("DIEAREA")) { - std::vector 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 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 @@ -223,37 +1243,10 @@ DEFImporter::do_read (db::Layout &layout) get_long (); expect (";"); - while (test ("-")) { + read_nondefaultrules (scale); - 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"); + expect ("END"); + expect ("NONDEFAULTRULES"); } else if (test ("REGIONS")) { @@ -261,37 +1254,10 @@ DEFImporter::do_read (db::Layout &layout) get_long (); expect (";"); - while (test ("-")) { + read_regions (regions, scale); - std::string n = get (); - std::vector &polygons = regions [n]; - - while (! peek (";")) { - - if (test ("+")) { - - // ignore other options for now - while (! peek (";")) { - take (); - } - break; - - } else { - - db::Polygon box; - read_rect (box, scale); - polygons.push_back (box); - - } - - } - - test (";"); - - } - - test ("END"); - test ("REGIONS"); + expect ("END"); + expect ("REGIONS"); } else if (test ("PINPROPERTIES")) { // read over PINPROPERTIES statements @@ -319,45 +1285,13 @@ DEFImporter::do_read (db::Layout &layout) get_long (); expect (";"); - while (test ("-")) { + read_groups (groups, scale); - std::string n = get (); - std::string rn; - std::vector match; - - while (! peek (";")) { - - if (test ("+")) { - - // gets the region name if there is one - if (test ("REGION")) { - rn = get (); - } - - // ignore the reset for now - while (! peek (";")) { - take (); - } - break; - - } else { - - match.push_back (tl::GlobPattern (get ())); - - } - - } - - groups.push_back (Group (n, rn, match)); - - test (";"); - - } - - test ("END"); - test ("GROUPS"); + expect ("END"); + expect ("GROUPS"); } else if (test ("BEGINEXT")) { + // read over BEGINEXT sections while (! test ("ENDEXT")) { take (); @@ -368,439 +1302,23 @@ DEFImporter::do_read (db::Layout &layout) get_long (); expect (";"); - while (test ("-")) { + read_blockages (layout, design, scale); - std::string layer; - - while (! test (";")) { - - if (test ("PLACEMENT")) { - - // indicates a placement blockage - layer = std::string (); - - } else if (test ("LAYER")) { - - layer = get (); - - } else if (test ("+")) { - - // ignore options for now - while (! peek ("RECT") && ! peek ("POLYGON") && ! peek ("+") && ! peek ("-") && ! peek (";")) { - take (); - } - - } else if (test ("POLYGON")) { - - db::Polygon p; - read_polygon (p, scale); - - std::pair dl = open_layer (layout, layer, layer.empty () ? PlacementBlockage : Blockage); - if (dl.first) { - design.shapes (dl.second).insert (p); - } - - } else if (test ("RECT")) { - - db::Polygon p; - read_rect (p, scale); - - std::pair dl = open_layer (layout, layer, layer.empty () ? PlacementBlockage : Blockage); - if (dl.first) { - design.shapes (dl.second).insert (p); - } - - } else { - expect (";"); - } - - } - - } - - test ("END"); - test ("BLOCKAGES"); + expect ("END"); + expect ("BLOCKAGES"); } else if ((specialnets = test ("SPECIALNETS")) == true || test ("NETS")) { get_long (); expect (";"); - while (test ("-")) { + read_nets (layout, design, scale, specialnets); - std::string net = get (); - std::string nondefaultrule; - std::string stored_netname, stored_nondefaultrule; - std::string taperrule; - bool in_subnet = false; - - db::properties_id_type prop_id = 0; - if (produce_net_props ()) { - db::PropertiesRepository::properties_set props; - props.insert (std::make_pair (net_prop_name_id (), tl::Variant (net))); - prop_id = layout.properties_repository ().properties_id (props); - } - - while (test ("(")) { - while (! test (")")) { - take (); - } - } - - while (test ("+")) { - - bool was_shield = false; - - if (! specialnets && test ("SUBNET")) { - - while (test ("(")) { - while (! test (")")) { - take (); - } - } - - if (! in_subnet) { - stored_netname = net; - stored_nondefaultrule = nondefaultrule; - in_subnet = true; - } - - } else if (! specialnets && test ("NONDEFAULTRULE")) { - - nondefaultrule = get (); - - } else if ((was_shield = test ("SHIELD")) == true || test ("NOSHIELD") || test ("ROUTED") || test ("FIXED") || test ("COVER")) { - - if (was_shield) { - take (); - } - - taperrule.clear (); - - do { - - std::string ln = get (); - - db::Coord w = 0; - if (specialnets) { - w = db::coord_traits::rounded (get_double () * scale); - } - - const db::Polygon *style = 0; - - int sn = std::numeric_limits::max (); - - if (specialnets) { - - while (test ("+")) { - - if (test ("STYLE")) { - sn = get_long (); - } else if (test ("SHAPE")) { - take (); - } - - } - - } else { - - while (true) { - if (test ("TAPER")) { - taperrule.clear (); - } else if (test ("TAPERRULE")) { - taperrule = get (); - } else if (test ("STYLE")) { - sn = get_long (); - } else { - break; - } - } - - } - - if (! specialnets) { - - const std::string *rulename = &taperrule; - if (rulename->empty ()) { - rulename = &nondefaultrule; - } - - w = db::coord_traits::rounded (m_lef_importer.layer_width (ln, *rulename, 0.0) / layout.dbu ()); - - // try to find local nondefault rule - if (! rulename->empty ()) { - std::map >::const_iterator nd = m_nondefault_widths.find (*rulename); - if (nd != m_nondefault_widths.end ()) { - std::map::const_iterator ld = nd->second.find (ln); - if (ld != nd->second.end ()) { - w = ld->second; - } - } - } - - } - - db::Coord def_ext = 0; - if (! specialnets) { - def_ext = db::coord_traits::rounded (m_lef_importer.layer_ext (ln, w * 0.5 * layout.dbu ()) / layout.dbu ()); - } - - std::map::const_iterator s = styles.find (sn); - if (s != styles.end ()) { - style = &s->second; - } - - std::vector ext; - std::vector pts; - - double x = 0.0, y = 0.0; - - while (true) { - - if (test ("MASK")) { - // ignore mask spec - get_long (); - } - - if (test ("RECT")) { - - if (! test ("(")) { - error (tl::to_string (tr ("RECT routing specification not followed by coordinate list"))); - } - - // breaks wiring - pts.clear (); - - // rect spec - - double x1 = get_double (); - double y1 = get_double (); - double x2 = get_double (); - double y2 = get_double (); - - test (")"); - - std::pair dl = open_layer (layout, ln, Routing); - if (dl.first) { - - db::Box rect (db::Point (db::DPoint ((x + x1) * scale, (y + y1) * scale)), - db::Point (db::DPoint ((x + x2) * scale, (y + y2) * scale))); - - if (prop_id != 0) { - design.shapes (dl.second).insert (db::object_with_properties (rect, prop_id)); - } else { - design.shapes (dl.second).insert (rect); - } - - } - - } else if (test ("VIRTUAL")) { - - // virtual specs simply create a new segment - pts.clear (); - - } else if (peek ("(")) { - - ext.clear (); - - while (peek ("(") || peek ("MASK")) { - - if (test ("MASK")) { - // ignore MASK spec - get_long (); - } - - if (! test ("(")) { - // We could have a via here: in that case we have swallowed MASK already, but - // since we don't do anything with that, this does not hurt for now. - break; - } - - if (! test ("*")) { - x = get_double (); - } - if (! test ("*")) { - y = get_double (); - } - pts.push_back (db::Point (db::DPoint (x * scale, y * scale))); - db::Coord e = def_ext; - if (! peek (")")) { - e = db::coord_traits::rounded (get_double () * scale); - } - ext.push_back (e); - - test (")"); - - } - - if (pts.size () > 1) { - - std::pair dl = open_layer (layout, ln, Routing); - if (dl.first) { - - if (! style) { - - // Use the default style (octagon "pen" for non-manhattan segments, paths for - // horizontal/vertical segments). - - db::Coord e = std::max (ext.front (), ext.back ()); - - std::vector::const_iterator pt = pts.begin (); - while (pt != pts.end ()) { - - std::vector::const_iterator pt0 = pt; - do { - ++pt; - } while (pt != pts.end () && (pt[-1].x () == pt[0].x () || pt[-1].y () == pt[0].y())); - - if (pt - pt0 > 1) { - - db::Path p (pt0, pt, w, pt0 == pts.begin () ? e : 0, pt == pts.end () ? e : 0, false); - if (prop_id != 0) { - design.shapes (dl.second).insert (db::object_with_properties (p, prop_id)); - } else { - design.shapes (dl.second).insert (p); - } - - if (pt == pts.end ()) { - break; - } - - --pt; - - } else if (pt != pts.end ()) { - - db::Coord s = (w + 1) / 2; - db::Coord t = db::Coord (ceil (w * (M_SQRT2 - 1) / 2)); - - db::Point octagon[8] = { - db::Point (-s, t), - db::Point (-t, s), - db::Point (t, s), - db::Point (s, t), - db::Point (s, -t), - db::Point (t, -s), - db::Point (-t, -s), - db::Point (-s, -t) - }; - - db::Polygon k; - k.assign_hull (octagon, octagon + sizeof (octagon) / sizeof (octagon[0])); - - db::Polygon p = db::minkowsky_sum (k, db::Edge (*pt0, *pt)); - if (prop_id != 0) { - design.shapes (dl.second).insert (db::object_with_properties (p, prop_id)); - } else { - design.shapes (dl.second).insert (p); - } - - } - - } - - } else { - - for (size_t i = 0; i < pts.size () - 1; ++i) { - db::Polygon p = db::minkowsky_sum (*style, db::Edge (pts [i], pts [i + 1])); - if (prop_id != 0) { - design.shapes (dl.second).insert (db::object_with_properties (p, prop_id)); - } else { - design.shapes (dl.second).insert (p); - } - } - - } - - } - - } - - } else if (! peek ("NEW") && ! peek ("+") && ! peek ("-") && ! peek (";")) { - - // indicates a via - std::string vn = get (); - db::FTrans ft = get_orient (true /*optional*/); - - std::map::const_iterator vd = via_desc.find (vn); - if (vd != via_desc.end () && ! pts.empty ()) { - design.insert (db::CellInstArray (db::CellInst (vd->second.cell->cell_index ()), db::Trans (ft.rot (), db::Vector (pts.back ())))); - if (ln == vd->second.m1) { - ln = vd->second.m2; - } else if (ln == vd->second.m2) { - ln = vd->second.m1; - } - } - - // continue a segment with the current point and the new layer - if (pts.size () > 1) { - pts.erase (pts.begin (), pts.end () - 1); - } - - } else { - break; - } - - } - - } while (test ("NEW")); - - if (in_subnet) { - in_subnet = false; - net = stored_netname; - stored_netname.clear (); - nondefaultrule = stored_nondefaultrule; - stored_nondefaultrule.clear (); - } - - } else if (test ("POLYGON")) { - - std::string ln = get (); - - db::Polygon p; - read_polygon (p, scale); - - std::pair dl = open_layer (layout, ln, Routing); - if (dl.first) { - if (prop_id != 0) { - design.shapes (dl.second).insert (db::object_with_properties (p, prop_id)); - } else { - design.shapes (dl.second).insert (p); - } - } - - } else if (test ("RECT")) { - - std::string ln = get (); - - db::Polygon p; - read_rect (p, scale); - - std::pair dl = open_layer (layout, ln, Routing); - if (dl.first) { - if (prop_id != 0) { - design.shapes (dl.second).insert (db::object_with_properties (p, prop_id)); - } else { - design.shapes (dl.second).insert (p); - } - } - - } else { - while (! peek ("+") && ! peek ("-") && ! peek (";")) { - take (); - } - } - - } - - expect (";"); - - } - - test ("END"); + expect ("END"); if (specialnets) { - test ("SPECIALNETS"); + expect ("SPECIALNETS"); } else { - test ("NETS"); + expect ("NETS"); } } else if (test ("VIAS")) { @@ -808,134 +1326,7 @@ DEFImporter::do_read (db::Layout &layout) get_long (); expect (";"); - while (test ("-")) { - - std::string n = get (); - ViaDesc &vd = via_desc.insert (std::make_pair (n, ViaDesc ())).first->second; - - // produce a cell for vias - std::string cellname = "VIA_" + n; - db::Cell &cell = layout.cell (layout.add_cell (cellname.c_str ())); - vd.cell = &cell; - - bool has_via_rule = false; - - db::Vector cutsize, cutspacing; - db::Vector be, te; - db::Vector bo, to; - db::Point offset; - int rows = 1, columns = 1; - std::string pattern; - - std::map > geometry; - std::vector *top = 0, *cut = 0, *bottom = 0; - - while (test ("+")) { - - double x, y; - - if (test ("VIARULE")) { - - has_via_rule = true; - take (); - - } else if (test ("CUTSIZE")) { - - x = get_double (); - y = get_double (); - cutsize = db::Vector (db::DVector (x * scale, y * scale)); - - } else if (test ("CUTSPACING")) { - - x = get_double (); - y = get_double (); - cutspacing = db::Vector (db::DVector (x * scale, y * scale)); - - } else if (test ("ORIGIN")) { - - x = get_double (); - y = get_double (); - offset = db::Point (db::DPoint (x * scale, y * scale)); - - } else if (test ("ENCLOSURE")) { - - x = get_double (); - y = get_double (); - be = db::Vector (db::DVector (x * scale, y * scale)); - - x = get_double (); - y = get_double (); - te = db::Vector (db::DVector (x * scale, y * scale)); - - } else if (test ("OFFSET")) { - - x = get_double (); - y = get_double (); - bo = db::Vector (db::DVector (x * scale, y * scale)); - - x = get_double (); - y = get_double (); - to = db::Vector (db::DVector (x * scale, y * scale)); - - } else if (test ("ROWCOL")) { - - rows = get_long (); - columns = get_long (); - - } else if (test ("PATTERN")) { - - pattern = get (); - - } else if (test ("LAYERS")) { - - std::string bn = get (); - std::string cn = get (); - std::string tn = get (); - - bottom = &geometry.insert (std::make_pair (bn, std::vector ())).first->second; - cut = &geometry.insert (std::make_pair (cn, std::vector ())).first->second; - top = &geometry.insert (std::make_pair (tn, std::vector ())).first->second; - - vd.m1 = bn; - vd.m2 = tn; - - } else if (test ("POLYGON")) { - - std::string ln = get (); - - std::vector &polygons = geometry.insert (std::make_pair (ln, std::vector ())).first->second; - polygons.push_back (db::Polygon ()); - read_polygon (polygons.back (), scale); - - } else if (test ("RECT")) { - - std::string ln = get (); - - std::vector &polygons = geometry.insert (std::make_pair (ln, std::vector ())).first->second; - polygons.push_back (db::Polygon ()); - read_rect (polygons.back (), scale); - - } - - } - - test (";"); - - if (has_via_rule && top && cut && bottom) { - create_generated_via (*bottom, *cut, *top, - cutsize, cutspacing, be, te, bo, to, offset, rows, columns, pattern); - } - - for (std::map >::const_iterator g = geometry.begin (); g != geometry.end (); ++g) { - std::pair dl = open_layer (layout, g->first, ViaGeometry); - if (dl.first) { - for (std::vector::const_iterator p = g->second.begin (); p != g->second.end (); ++p) { - cell.shapes (dl.second).insert (*p); - } - } - } - - } + read_vias (layout, design, scale); expect ("END"); expect ("VIAS"); @@ -945,80 +1336,17 @@ DEFImporter::do_read (db::Layout &layout) get_long (); expect (";"); - while (test ("-")) { + read_styles (scale); - test ("STYLE"); - - int sn = get_long (); - - std::vector points; - - double x = 0.0, y = 0.0; - - while (! test (";")) { - - test ("("); - if (! test ("*")) { - x = get_double (); - } - if (! test ("*")) { - y = get_double (); - } - points.push_back (db::Point (db::DPoint (x * scale, y * scale))); - test (")"); - - } - - styles.insert (std::make_pair (sn, db::Polygon ())).first->second.assign_hull (points.begin (), points.end ()); - - } - - test ("END"); - test ("STYLES"); + expect ("END"); + expect ("STYLES"); } else if (test ("COMPONENTS")) { get_long (); expect (";"); - while (test ("-")) { - - std::string inst_name = get (); - std::string model = get (); - - db::Cell *cell = m_lef_importer.macro_by_name (model); - - while (test ("+")) { - - if (test ("PLACED") || test ("FIXED") || test ("COVER")) { - - test ("("); - double x = get_double (); - double y = get_double (); - db::Point pt = db::Point (db::DPoint (x * scale, y * scale)); - test (")"); - - db::FTrans ft = get_orient (false /*mandatory*/); - db::Vector d = pt - m_lef_importer.macro_bbox_by_name (model).transformed (ft).lower_left (); - - if (cell) { - db::CellInstArray inst (db::CellInst (cell->cell_index ()), db::Trans (ft.rot (), d)); - instances.push_back (std::make_pair (inst_name, inst)); - } else { - warn (tl::to_string (tr ("Macro not found in LEF file: ")) + model); - } - - } else { - while (! peek ("+") && ! peek ("-") && ! peek (";")) { - take (); - } - } - - } - - expect (";"); - - } + read_components (instances, scale); expect ("END"); expect ("COMPONENTS"); @@ -1028,154 +1356,7 @@ DEFImporter::do_read (db::Layout &layout) get_long (); expect (";"); - while (test ("-")) { - - take (); // pin name - - std::string net; - std::string dir; - std::map > geometry; - db::Trans trans; - - while (test ("+")) { - - bool flush = false; - - if (test ("DIRECTION")) { - dir = get (); - } else if (test ("NET")) { - net = get (); - } else if (test ("LAYER")) { - - std::string ln = get (); - - while (test ("DESIGNRULEWIDTH") || test ("SPACING")) { - take (); - } - - double x, y; - - test ("("); - x = get_double (); - y = get_double (); - db::Point pt1 = db::Point (db::DPoint (x * scale, y * scale)); - test (")"); - - test ("("); - x = get_double (); - y = get_double (); - db::Point pt2 = db::Point (db::DPoint (x * scale, y * scale)); - test (")"); - - geometry.insert (std::make_pair (ln, std::vector ())).first->second.push_back (db::Polygon (db::Box (pt1, pt2))); - - } else if (test ("POLYGON")) { - - std::string ln = get (); - - while (test ("DESIGNRULEWIDTH") || test ("SPACING")) { - take (); - } - - std::vector points; - - double x = 0.0, y = 0.0; - - while (! test ("+") && ! test (";")) { - - test ("("); - if (! test ("*")) { - x = get_double (); - } - if (! test ("*")) { - y = get_double (); - } - points.push_back (db::Point (db::DPoint (x * scale, y * scale))); - test (")"); - - } - - std::vector &polygons = geometry.insert (std::make_pair (ln, std::vector ())).first->second; - polygons.push_back (db::Polygon ()); - polygons.back ().assign_hull (points.begin (), points.end ()); - - } else if (test ("PLACED") || test ("FIXED") || test ("COVER")) { - - test ("("); - double x = get_double (); - double y = get_double (); - db::Vector d = db::Vector (db::DVector (x * scale, y * scale)); - test (")"); - - db::FTrans ft = get_orient (false /*mandatory*/); - trans = db::Trans (ft.rot (), d); - - } else if (test ("PORT")) { - - flush = true; - - } else { - while (! peek ("+") && ! peek ("-") && ! peek (";")) { - take (); - } - } - - if (flush || ! peek ("+")) { - - // TODO: put a label on every single object? - std::string label = net; - /* don't add the direction currently, a name is sufficient - if (! dir.empty ()) { - label += ":"; - label += dir; - } - */ - - // Produce geometry collected so far - for (std::map >::const_iterator g = geometry.begin (); g != geometry.end (); ++g) { - - std::pair dl = open_layer (layout, g->first, Pins); - if (dl.first) { - - 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); - } - - for (std::vector::const_iterator p = g->second.begin (); p != g->second.end (); ++p) { - db::Polygon pt = p->transformed (trans); - if (prop_id == 0) { - design.shapes (dl.second).insert (pt); - } else { - design.shapes (dl.second).insert (db::PolygonWithProperties (pt, prop_id)); - } - } - - } - - dl = open_layer (layout, g->first, Label); - if (dl.first) { - db::Box bbox; - if (! g->second.empty ()) { - bbox = g->second.back ().box ().transformed (trans); - } - design.shapes (dl.second).insert (db::Text (label.c_str (), db::Trans (db::Vector (bbox.center ())))); - } - - } - - geometry.clear (); - trans = db::Trans (); - - } - - } - - expect (";"); - - } + read_pins (layout, design, scale); expect ("END"); expect ("PINS"); @@ -1193,7 +1374,9 @@ DEFImporter::do_read (db::Layout &layout) db::Cell *others_cell = &design; - if (! groups.empty ()) { + if (! groups.empty () && options ().separate_groups ()) { + + db::LayoutLocker locker (&layout); others_cell = &layout.cell (layout.add_cell ("NOGROUP")); design.insert (db::CellInstArray (others_cell->cell_index (), db::Trans ())); @@ -1201,23 +1384,28 @@ DEFImporter::do_read (db::Layout &layout) // Walk through the groups, create a group container cell and put all instances // that match the group match string there. Then delete these cells (spec says "do not assign any component to more than one group"). - for (std::list::const_iterator g = groups.begin (); g != groups.end (); ++g) { + for (std::list::const_iterator g = groups.begin (); g != groups.end (); ++g) { db::Cell *group_cell = &layout.cell (layout.add_cell (("GROUP_" + g->name).c_str ())); design.insert (db::CellInstArray (group_cell->cell_index (), db::Trans ())); if (! g->region_name.empty ()) { - std::map >::const_iterator r = regions.find (g->region_name); + std::map >::iterator r = regions.find (g->region_name); if (r == regions.end ()) { - warn (tl::sprintf (tl::to_string (tr ("Not a valid region name: %s in group %s")), g->region_name, g->name)); + + warn (tl::sprintf (tl::to_string (tr ("Not a valid region name or region is already used: %s in group %s")), g->region_name, g->name)); + } else { - std::pair dl = open_layer (layout, std::string (), Region); + + std::pair dl = open_layer (layout, std::string (), Regions); if (dl.first) { for (std::vector::const_iterator p = r->second.begin (); p != r->second.end (); ++p) { group_cell->shapes (dl.second).insert (*p); } } + regions.erase (r); + } } @@ -1249,6 +1437,23 @@ DEFImporter::do_read (db::Layout &layout) } + // put all remaining regions into the "others_cell" which is the top cell if there are no groups. + + if (! regions.empty ()) { + + std::pair dl = open_layer (layout, std::string (), Regions); + if (dl.first) { + + for (std::map >::const_iterator r = regions.begin (); r != regions.end (); ++r) { + for (std::vector::const_iterator p = r->second.begin (); p != r->second.end (); ++p) { + others_cell->shapes (dl.second).insert (*p); + } + } + + } + + } + // treat all remaining cells and put them into the "others_cell" which is the top cell // if there are no groups. @@ -1266,4 +1471,3 @@ DEFImporter::do_read (db::Layout &layout) } } - diff --git a/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.h b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.h index 112098cbc..dc9e36488 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.h +++ b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.h @@ -36,6 +36,8 @@ namespace db { +struct DEFImporterGroup; + /** * @brief The DEF importer object */ @@ -54,18 +56,33 @@ public: * This method reads the layout specified into the given layout. * Multiple LEF files can be read. */ - void read_lef (tl::InputStream &stream, db::Layout &layout, LEFDEFLayerDelegate &ld); + void read_lef (tl::InputStream &stream, db::Layout &layout, LEFDEFReaderState &state); protected: void do_read (db::Layout &layout); private: LEFImporter m_lef_importer; - std::map > m_nondefault_widths; + std::map > m_nondefault_widths; + std::map m_via_desc; + std::map m_styles; - db::FTrans get_orient (bool optional); void read_polygon (db::Polygon &poly, double scale); void read_rect (db::Polygon &poly, double scale); + std::pair get_wire_width_for_rule(const std::string &rule, const std::string &ln, double dbu); + std::pair get_def_ext (const std::string &ln, const std::pair &wxy, double dbu); + void read_diearea (db::Layout &layout, db::Cell &design, double scale); + void read_nondefaultrules (double scale); + void read_regions (std::map > ®ions, double scale); + void read_groups (std::list &groups, double scale); + void read_blockages (db::Layout &layout, db::Cell &design, double scale); + void read_nets (db::Layout &layout, db::Cell &design, double scale, bool specialnets); + void read_vias (db::Layout &layout, db::Cell &design, double scale); + void read_pins (db::Layout &layout, db::Cell &design, double scale); + void read_styles (double scale); + void read_components (std::list > &instances, double scale); + void read_single_net (std::string &nondefaultrule, db::Layout &layout, db::Cell &design, double scale, properties_id_type prop_id, bool specialnets); + void produce_routing_geometry (db::Cell &design, const db::Polygon *style, unsigned int layer, properties_id_type prop_id, const std::vector &pts, const std::vector > &ext, std::pair w); }; } diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc index df62aa388..61223bb34 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc @@ -22,9 +22,11 @@ #include "dbLEFDEFImporter.h" +#include "dbLayoutUtils.h" #include "tlStream.h" #include "tlProgress.h" +#include "tlFileUtils.h" #include @@ -52,9 +54,13 @@ LEFDEFReaderOptions::LEFDEFReaderOptions () m_produce_via_geometry (true), m_via_geometry_suffix (""), m_via_geometry_datatype (0), + m_via_cellname_prefix ("VIA_"), m_produce_pins (true), m_pins_suffix (".PIN"), m_pins_datatype (2), + m_produce_lef_pins (true), + m_lef_pins_suffix (".PIN"), + m_lef_pins_datatype (2), m_produce_obstructions (true), m_obstructions_suffix (".OBS"), m_obstructions_datatype (3), @@ -66,7 +72,13 @@ LEFDEFReaderOptions::LEFDEFReaderOptions () m_labels_datatype (1), m_produce_routing (true), m_routing_suffix (""), - m_routing_datatype (0) + m_routing_datatype (0), + m_produce_special_routing (true), + m_special_routing_suffix (""), + m_special_routing_datatype (0), + m_separate_groups (false), + m_map_file (), + m_macro_resolution_mode (0) { // .. nothing yet .. } @@ -99,9 +111,13 @@ LEFDEFReaderOptions &LEFDEFReaderOptions::operator= (const LEFDEFReaderOptions & m_produce_via_geometry = d.m_produce_via_geometry; m_via_geometry_suffix = d.m_via_geometry_suffix; m_via_geometry_datatype = d.m_via_geometry_datatype; + m_via_cellname_prefix = d.m_via_cellname_prefix; m_produce_pins = d.m_produce_pins; m_pins_suffix = d.m_pins_suffix; m_pins_datatype = d.m_pins_datatype; + m_produce_lef_pins = d.m_produce_lef_pins; + m_lef_pins_suffix = d.m_lef_pins_suffix; + m_lef_pins_datatype = d.m_lef_pins_datatype; m_produce_obstructions = d.m_produce_obstructions; m_obstructions_suffix = d.m_obstructions_suffix; m_obstructions_datatype = d.m_obstructions_datatype; @@ -114,6 +130,12 @@ LEFDEFReaderOptions &LEFDEFReaderOptions::operator= (const LEFDEFReaderOptions & m_produce_routing = d.m_produce_routing; m_routing_suffix = d.m_routing_suffix; m_routing_datatype = d.m_routing_datatype; + m_produce_special_routing = d.m_produce_special_routing; + m_special_routing_suffix = d.m_special_routing_suffix; + m_special_routing_datatype = d.m_special_routing_datatype; + m_separate_groups = d.m_separate_groups; + m_map_file = d.m_map_file; + m_macro_resolution_mode = d.m_macro_resolution_mode; m_lef_files = d.m_lef_files; } return *this; @@ -135,37 +157,194 @@ LEFDEFReaderOptions::format_name () const // ----------------------------------------------------------------------------------- // LEFDEFLayerDelegate implementation -LEFDEFLayerDelegate::LEFDEFLayerDelegate (const LEFDEFReaderOptions *tc) - : m_create_layers (true), m_laynum (1), mp_tech_comp (tc) +LEFDEFReaderState::LEFDEFReaderState (const LEFDEFReaderOptions *tc, db::Layout &layout) + : m_create_layers (true), m_has_explicit_layer_mapping (false), m_laynum (1), mp_tech_comp (tc) { if (tc) { m_layer_map = tc->layer_map (); m_create_layers = tc->read_all_layers (); } + + m_layer_map.prepare (layout); } void -LEFDEFLayerDelegate::register_layer (const std::string &ln) +LEFDEFReaderState::register_layer (const std::string &ln) { m_default_number.insert (std::make_pair (ln, m_laynum)); ++m_laynum; } -std::pair -LEFDEFLayerDelegate::open_layer (db::Layout &layout, const std::string &n, LayerPurpose purpose) +void +LEFDEFReaderState::set_explicit_layer_mapping (bool f) { - if (purpose == Outline || purpose == PlacementBlockage || purpose == Region) { + m_has_explicit_layer_mapping = f; + if (! f) { + m_layers.clear (); + } +} +void +LEFDEFReaderState::map_layer_explicit (const std::string &n, LayerPurpose purpose, const db::LayerProperties &lp, unsigned int layer) +{ + m_layers [std::make_pair (n, purpose)] = std::make_pair (true, layer); + m_layer_map.map (lp, layer); +} + +void +LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout) +{ + tl::log << tl::to_string (tr ("Reading LEF/DEF map file")) << " " << path; + + tl::InputFile file (path); + tl::InputStream file_stream (file); + tl::TextInputStream ts (file_stream); + + std::map purpose_translation; + purpose_translation ["LEFPIN"] = LEFPins; + purpose_translation ["PIN"] = Pins; + purpose_translation ["LEFOBS"] = Obstructions; + purpose_translation ["SPNET"] = SpecialRouting; + purpose_translation ["NET"] = Routing; + purpose_translation ["VIA"] = ViaGeometry; + purpose_translation ["BLOCKAGE"] = Blockage; + + std::map, db::LayerProperties> layer_map; + + while (! ts.at_end ()) { + + const std::string &l = ts.get_line (); + + tl::Extractor ex (l.c_str ()); + if (ex.at_end () || ex.test ("#")) { + + // ignore empty of comment lines + + } else { + + std::string w1, w2; + int layer = 0, datatype = 0; + + if (ex.try_read_word (w1) && ex.try_read_word (w2, "._$,/:") && ex.try_read (layer) && ex.try_read (datatype)) { + + if (w1 == "DIEAREA") { + + layer_map [std::make_pair (std::string (), Outline)] = db::LayerProperties (layer, datatype, "OUTLINE"); + + } else if (w1 == "REGIONS") { + + layer_map [std::make_pair (std::string (), Regions)] = db::LayerProperties (layer, datatype, "REGIONS"); + + } else if (w1 == "BLOCKAGE") { + + layer_map [std::make_pair (std::string (), PlacementBlockage)] = db::LayerProperties (layer, datatype, "PLACEMENT_BLK"); + + } else if (w1 == "NAME") { + + // converts a line like + // "NAME M1/PINS,M2/PINS ..." + // into a canonical name mapping like + // "(M1/LABELS): M1.LABEL" + // "(M2/LABELS): M2.LABEL" + + std::vector layers; + std::vector purposes = tl::split (w2, ","); + for (std::vector::const_iterator p = purposes.begin (); p != purposes.end (); ++p) { + layers.push_back (tl::split (*p, "/").front ()); + } + + std::string final_name = tl::join (layers, "/") + ".LABEL"; + for (std::vector::const_iterator l = layers.begin (); l != layers.end (); ++l) { + layer_map [std::make_pair (*l, Label)] = db::LayerProperties (layer, datatype, final_name); + } + + } else { + + // converts a line like + // "M1 SPNET,NET,PINS,LEFPINS ..." + // into a canonical name mapping like + // "(M1,NET): M1.NET/PINS" + // "(M1,PINS): M1.NET/PINS" + // (separating, translating and recombing the purposes) + + std::set translated_purposes; + std::string purpose_str; + std::vector purposes = tl::split (w2, ","); + for (std::vector::const_iterator p = purposes.begin (); p != purposes.end (); ++p) { + + std::map::const_iterator i = purpose_translation.find (tl::to_upper_case (*p)); + if (i != purpose_translation.end ()) { + + translated_purposes.insert (i->second); + + if (! purpose_str.empty ()) { + purpose_str += "/"; + } + purpose_str += i->first; + + } + } + + std::string final_name = w1 + "." + purpose_str; + + for (std::set::const_iterator p = translated_purposes.begin (); p != translated_purposes.end (); ++p) { + layer_map [std::make_pair (w1, *p)] = db::LayerProperties (layer, datatype, final_name); + } + + } + + } + + } + + } + + set_explicit_layer_mapping (true); + + db::DirectLayerMapping lm (&layout); + for (std::map, db::LayerProperties>::const_iterator i = layer_map.begin (); i != layer_map.end (); ++i) { + map_layer_explicit (i->first.first, i->first.second, i->second, lm.map_layer (i->second).second); + } +} + +std::pair +LEFDEFReaderState::open_layer (db::Layout &layout, const std::string &n, LayerPurpose purpose) +{ + std::map , std::pair >::const_iterator nl = m_layers.find (std::make_pair (n, purpose)); + if (nl == m_layers.end ()) { + + std::pair ll (false, 0); + + if (n.empty () || ! m_has_explicit_layer_mapping) { + ll = open_layer_uncached (layout, n, purpose); + } + + m_layers.insert (std::make_pair (std::make_pair (n, purpose), ll)); + return ll; + + } else { + return nl->second; + } +} + +std::pair +LEFDEFReaderState::open_layer_uncached (db::Layout &layout, const std::string &n, LayerPurpose purpose) +{ + if (n.empty ()) { + + // NOTE: the canonical name is independent from the tech component's settings + // as is "(name)". It's used for implementing the automatic map file import + // feature. std::string ld; - bool produce; + bool produce = false; if (purpose == Outline) { produce = mp_tech_comp->produce_cell_outlines (); ld = mp_tech_comp->cell_outline_layer (); - } else if (purpose == Region) { + } else if (purpose == Regions) { produce = mp_tech_comp->produce_regions (); ld = mp_tech_comp->region_layer (); - } else { + } else if (purpose == PlacementBlockage) { produce = mp_tech_comp->produce_placement_blockages (); ld = mp_tech_comp->placement_blockage_layer (); } @@ -187,11 +366,6 @@ LEFDEFLayerDelegate::open_layer (db::Layout &layout, const std::string &n, Layer if (ll.first) { - // create the layer if it is not part of the layout yet. - if (! layout.is_valid_layer (ll.second)) { - layout.insert_layer (ll.second, m_layer_map.mapping (ll.second)); - } - return ll; } else if (! m_create_layers) { @@ -208,67 +382,95 @@ LEFDEFLayerDelegate::open_layer (db::Layout &layout, const std::string &n, Layer } else { + if (mp_tech_comp) { + bool produce = true; + switch (purpose) { + case Routing: + default: + produce = mp_tech_comp->produce_routing (); + break; + case SpecialRouting: + produce = mp_tech_comp->produce_special_routing (); + break; + case ViaGeometry: + produce = mp_tech_comp->produce_via_geometry (); + break; + case Label: + produce = mp_tech_comp->produce_labels (); + break; + case Pins: + produce = mp_tech_comp->produce_pins (); + break; + case LEFPins: + produce = mp_tech_comp->produce_lef_pins (); + break; + case Obstructions: + produce = mp_tech_comp->produce_obstructions (); + break; + case Blockage: + produce = mp_tech_comp->produce_blockages (); + break; + } + if (! produce) { + return std::make_pair (false, 0); + } + } + + // Note: "name" is the decorated name as provided by the tech component's + // x_suffix specifications. std::string name (n); - bool produce = true; int dt = 0; if (mp_tech_comp) { switch (purpose) { case Routing: default: - produce = mp_tech_comp->produce_routing (); name += mp_tech_comp->routing_suffix (); dt += mp_tech_comp->routing_datatype (); break; + case SpecialRouting: + name += mp_tech_comp->special_routing_suffix (); + dt += mp_tech_comp->special_routing_datatype (); + break; case ViaGeometry: - produce = mp_tech_comp->produce_via_geometry (); name += mp_tech_comp->via_geometry_suffix (); dt += mp_tech_comp->via_geometry_datatype (); break; case Label: - produce = mp_tech_comp->produce_labels (); name += mp_tech_comp->labels_suffix (); dt += mp_tech_comp->labels_datatype (); break; case Pins: - produce = mp_tech_comp->produce_pins (); name += mp_tech_comp->pins_suffix (); dt += mp_tech_comp->pins_datatype (); break; + case LEFPins: + name += mp_tech_comp->lef_pins_suffix (); + dt += mp_tech_comp->lef_pins_datatype (); + break; case Obstructions: - produce = mp_tech_comp->produce_obstructions (); name += mp_tech_comp->obstructions_suffix (); dt += mp_tech_comp->obstructions_datatype (); break; case Blockage: - produce = mp_tech_comp->produce_blockages (); name += mp_tech_comp->blockages_suffix (); dt += mp_tech_comp->blockages_datatype (); break; } } - if (! produce) { - return std::make_pair (false, 0); - } - std::pair ll = m_layer_map.logical (name, layout); if (ll.first) { - // create the layer if it is not part of the layout yet. - if (! layout.is_valid_layer (ll.second)) { - layout.insert_layer (ll.second, m_layer_map.mapping (ll.second)); - } - return ll; } else { - std::pair ll_raw = m_layer_map.logical (n, layout); + ll = m_layer_map.logical (n, layout); int ln = -1; - if (ll_raw.first && (ln = layout.get_properties (ll_raw.second).layer) >= 0) { + if (ll.first && (ln = layout.get_properties (ll.second).layer) >= 0) { m_layer_map.map (db::LayerProperties (name), layout.layers (), db::LayerProperties (ln, dt, name)); m_layer_map.prepare (layout); @@ -280,14 +482,14 @@ LEFDEFLayerDelegate::open_layer (db::Layout &layout, const std::string &n, Layer } else { - std::map , unsigned int>::const_iterator nl = m_layers.find (std::make_pair (n, purpose)); - if (nl == m_layers.end ()) { - unsigned int li = layout.insert_layer (db::LayerProperties (name)); - m_layer_map.map (db::LayerProperties (name), li); - m_layers.insert (std::make_pair (std::make_pair (n, purpose), li)); - return std::pair (true, li); + std::map , unsigned int>::const_iterator l = m_unassigned_layers.find (std::make_pair (n, purpose)); + if (l != m_unassigned_layers.end ()) { + return std::pair (true, l->second); } else { - return std::pair (true, nl->second); + unsigned int li = layout.insert_layer (db::LayerProperties (name)); + m_unassigned_layers.insert (std::make_pair (std::make_pair (n, purpose), li)); + m_layer_map.map (db::LayerProperties (name), li); + return std::pair (true, li); } } @@ -298,13 +500,7 @@ LEFDEFLayerDelegate::open_layer (db::Layout &layout, const std::string &n, Layer } void -LEFDEFLayerDelegate::prepare (db::Layout &layout) -{ - m_layer_map.prepare (layout); -} - -void -LEFDEFLayerDelegate::finish (db::Layout &layout) +LEFDEFReaderState::finish (db::Layout &layout) { int lnum = 0; @@ -319,7 +515,7 @@ LEFDEFLayerDelegate::finish (db::Layout &layout) used_numbers.insert (ln->second); } - for (std::map, unsigned int>::const_iterator l = m_layers.begin (); l != m_layers.end (); ++l) { + for (std::map, unsigned int>::const_iterator l = m_unassigned_layers.begin (); l != m_unassigned_layers.end (); ++l) { int dt = 0; switch (l->first.second) { @@ -327,6 +523,9 @@ LEFDEFLayerDelegate::finish (db::Layout &layout) default: dt = mp_tech_comp->routing_datatype (); break; + case SpecialRouting: + dt = mp_tech_comp->special_routing_datatype (); + break; case ViaGeometry: dt = mp_tech_comp->via_geometry_datatype (); break; @@ -336,6 +535,9 @@ LEFDEFLayerDelegate::finish (db::Layout &layout) case Pins: dt = mp_tech_comp->pins_datatype (); break; + case LEFPins: + dt = mp_tech_comp->lef_pins_datatype (); + break; case Obstructions: dt = mp_tech_comp->obstructions_datatype (); break; @@ -364,11 +566,24 @@ LEFDEFLayerDelegate::finish (db::Layout &layout) } } +void +LEFDEFReaderState::register_via_cell (const std::string &vn, db::Cell *cell) +{ + m_via_cells [vn] = cell; +} + +db::Cell * +LEFDEFReaderState::via_cell (const std::string &vn) +{ + std::map::const_iterator i = m_via_cells.find (vn); + return i != m_via_cells.end () ? i->second : 0; +} + // ----------------------------------------------------------------------------------- // LEFDEFImporter implementation LEFDEFImporter::LEFDEFImporter () - : mp_progress (0), mp_stream (0), mp_layer_delegate (0), + : mp_progress (0), mp_stream (0), mp_reader_state (0), m_produce_net_props (false), m_net_prop_name_id (0), m_produce_inst_props (false), m_inst_prop_name_id (0), m_produce_pin_props (false), m_pin_prop_name_id (0) @@ -382,7 +597,7 @@ LEFDEFImporter::~LEFDEFImporter () } void -LEFDEFImporter::read (tl::InputStream &stream, db::Layout &layout, LEFDEFLayerDelegate &ld) +LEFDEFImporter::read (tl::InputStream &stream, db::Layout &layout, LEFDEFReaderState &state) { m_fn = stream.filename (); @@ -391,34 +606,39 @@ LEFDEFImporter::read (tl::InputStream &stream, db::Layout &layout, LEFDEFLayerDe progress.set_format_unit (1000.0); progress.set_unit (10000.0); + mp_reader_state = &state; + + if (state.tech_comp ()) { + m_options = *state.tech_comp (); + } + m_produce_net_props = false; m_net_prop_name_id = 0; - if (ld.tech_comp () && ld.tech_comp ()->produce_net_names ()) { + if (m_options.produce_net_names ()) { m_produce_net_props = true; - m_net_prop_name_id = layout.properties_repository ().prop_name_id (ld.tech_comp ()->net_property_name ()); + m_net_prop_name_id = layout.properties_repository ().prop_name_id (m_options.net_property_name ()); } m_produce_inst_props = false; m_inst_prop_name_id = 0; - if (ld.tech_comp () && ld.tech_comp ()->produce_inst_names ()) { + if (m_options.produce_inst_names ()) { m_produce_inst_props = true; - m_inst_prop_name_id = layout.properties_repository ().prop_name_id (ld.tech_comp ()->inst_property_name ()); + m_inst_prop_name_id = layout.properties_repository ().prop_name_id (m_options.inst_property_name ()); } m_produce_pin_props = false; m_pin_prop_name_id = 0; - if (ld.tech_comp () && ld.tech_comp ()->produce_pin_names ()) { + if (m_options.produce_pin_names ()) { m_produce_pin_props = true; - m_pin_prop_name_id = layout.properties_repository ().prop_name_id (ld.tech_comp ()->pin_property_name ()); + m_pin_prop_name_id = layout.properties_repository ().prop_name_id (m_options.pin_property_name ()); } try { mp_progress = &progress; - mp_layer_delegate = &ld; mp_stream = new tl::TextInputStream (stream); do_read (layout); @@ -502,7 +722,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 () { if (m_last_token.empty ()) { @@ -763,5 +999,48 @@ LEFDEFImporter::create_generated_via (std::vector &bottom, } +db::FTrans +LEFDEFImporter::get_orient (bool optional) +{ + if (test ("N")) { + return db::FTrans (db::FTrans::r0); + } else if (test ("S")) { + return db::FTrans (db::FTrans::r180); + } else if (test ("W")) { + return db::FTrans (db::FTrans::r90); + } else if (test ("E")) { + return db::FTrans (db::FTrans::r270); + } else if (test ("FN")) { + return db::FTrans (db::FTrans::m90); + } else if (test ("FS")) { + return db::FTrans (db::FTrans::m0); + } else if (test ("FW")) { + return db::FTrans (db::FTrans::m45); + } else if (test ("FE")) { + return db::FTrans (db::FTrans::m135); + } else if (optional) { + return db::FTrans (db::FTrans::r0); + } else { + error (tl::to_string (tr ("Invalid orientation specification: ")) + get ()); + return db::FTrans (db::FTrans::r0); + } +} + +db::Point +LEFDEFImporter::get_point (double scale) +{ + double x = get_double (); + double y = get_double (); + return db::Point (db::DPoint (x * scale, y * scale)); +} + +db::Vector +LEFDEFImporter::get_vector (double scale) +{ + double x = get_double (); + double y = get_double (); + return db::Vector (db::DVector (x * scale, y * scale)); +} + } diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h index 9a9d63b9c..22858f048 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h @@ -256,6 +256,16 @@ public: m_via_geometry_datatype = s; } + const std::string &via_cellname_prefix () const + { + return m_via_cellname_prefix; + } + + void set_via_cellname_prefix (const std::string &s) + { + m_via_cellname_prefix = s; + } + bool produce_pins () const { return m_produce_pins; @@ -286,6 +296,36 @@ public: m_pins_datatype = s; } + bool produce_lef_pins () const + { + return m_produce_lef_pins; + } + + void set_produce_lef_pins (bool f) + { + m_produce_lef_pins = f; + } + + const std::string &lef_pins_suffix () const + { + return m_lef_pins_suffix; + } + + void set_lef_pins_suffix (const std::string &s) + { + m_lef_pins_suffix = s; + } + + int lef_pins_datatype () const + { + return m_lef_pins_datatype; + } + + void set_lef_pins_datatype (int s) + { + m_lef_pins_datatype = s; + } + bool produce_obstructions () const { return m_produce_obstructions; @@ -406,6 +446,36 @@ public: m_routing_datatype = s; } + bool produce_special_routing () const + { + return m_produce_special_routing; + } + + void set_produce_special_routing (bool f) + { + m_produce_special_routing = f; + } + + const std::string &special_routing_suffix () const + { + return m_special_routing_suffix; + } + + void set_special_routing_suffix (const std::string &s) + { + m_special_routing_suffix = s; + } + + int special_routing_datatype () const + { + return m_special_routing_datatype; + } + + void set_special_routing_datatype (int s) + { + m_special_routing_datatype = s; + } + void clear_lef_files () { m_lef_files.clear (); @@ -436,6 +506,43 @@ public: m_lef_files = lf; } + bool separate_groups () const + { + return m_separate_groups; + } + + void set_separate_groups (bool f) + { + m_separate_groups = f; + } + + const std::string &map_file () const + { + return m_map_file; + } + + void set_map_file (const std::string &f) + { + m_map_file = f; + } + + /** + * @brief Specify the LEF macro resolution strategy + * Values are: + * 0: propduce LEF geometry unless a FOREIGN cell is specified (default) + * 1: produce LEF geometry always and ignore FOREIGN + * 2: produce a placeholder cell always (even if FOREIGN isn't given) + */ + unsigned int macro_resolution_mode () const + { + return m_macro_resolution_mode; + } + + void set_macro_resolution_mode (unsigned int m) + { + m_macro_resolution_mode = m; + } + private: bool m_read_all_layers; db::LayerMap m_layer_map; @@ -455,9 +562,13 @@ private: bool m_produce_via_geometry; std::string m_via_geometry_suffix; int m_via_geometry_datatype; + std::string m_via_cellname_prefix; bool m_produce_pins; std::string m_pins_suffix; int m_pins_datatype; + bool m_produce_lef_pins; + std::string m_lef_pins_suffix; + int m_lef_pins_datatype; bool m_produce_obstructions; std::string m_obstructions_suffix; int m_obstructions_datatype; @@ -470,6 +581,12 @@ private: bool m_produce_routing; std::string m_routing_suffix; int m_routing_datatype; + bool m_produce_special_routing; + std::string m_special_routing_suffix; + int m_special_routing_datatype; + bool m_separate_groups; + std::string m_map_file; + unsigned int m_macro_resolution_mode; std::vector m_lef_files; }; @@ -478,15 +595,17 @@ private: */ enum LayerPurpose { - Routing = 0, - ViaGeometry = 1, - Label = 2, - Pins = 3, - Obstructions = 4, - Outline = 5, - Blockage = 6, - PlacementBlockage = 7, - Region = 8 + Routing = 0, // from DEF only + SpecialRouting, // from DEF only + ViaGeometry, // from LEF+DEF + Label, // from LEF+DEF + Pins, // from DEF + LEFPins, // from LEF + Obstructions, // from LEF only + Outline, // from LEF+DEF + Blockage, // from DEF only + PlacementBlockage, // from DEF only + Regions, // from DEF only }; /** @@ -494,16 +613,33 @@ enum LayerPurpose * * This class will handle the creation and management of layers in the LEF/DEF reader context */ -class DB_PLUGIN_PUBLIC LEFDEFLayerDelegate +class DB_PLUGIN_PUBLIC LEFDEFReaderState { public: /** * @brief Constructor */ - LEFDEFLayerDelegate (const LEFDEFReaderOptions *tc); + LEFDEFReaderState (const LEFDEFReaderOptions *tc, db::Layout &layout); /** - * @brief Set the layer map + * @brief Provides an explicit layer mapping + * This method is used when reading the layer map file. + */ + void map_layer_explicit (const std::string &n, LayerPurpose purpose, const LayerProperties &lp, unsigned int layer); + + /** + * @brief Provides an explicit layer mapping + * If this flag is set, the layer mapping specified in the reader options are ignored. + */ + void set_explicit_layer_mapping (bool f); + + /** + * @brief Reads a map file + */ + void read_map_file (const std::string &path, db::Layout &layout); + + /** + * @brief Sets the layer map */ virtual void set_layer_map (const db::LayerMap &lm, bool create_layers) { @@ -512,13 +648,21 @@ public: } /** - * @brief Get the layer map + * @brief Gets the layer map */ const db::LayerMap &layer_map () const { return m_layer_map; } + /** + * @brief Gets the layer map (non-const version) + */ + db::LayerMap &layer_map () + { + return m_layer_map; + } + /** * @brief Create a new layer or return the index of the given layer */ @@ -529,16 +673,21 @@ public: */ void register_layer (const std::string &l); - /** - * @brief Prepare, i.e. create layers required by the layer map - */ - void prepare (db::Layout &layout); - /** * @brief Finish, i.e. assign GDS layer numbers to the layers */ void finish (db::Layout &layout); + /** + * @brief Registers a via cell for the via with the given name + */ + void register_via_cell (const std::string &vn, db::Cell *cell); + + /** + * @brief Gets the via cell for the given via name or 0 if no such via is registered + */ + db::Cell *via_cell (const std::string &vn); + /** * @brief Get the technology component pointer */ @@ -548,12 +697,17 @@ public: } private: - std::map , unsigned int> m_layers; + std::map , std::pair > m_layers; + std::map , unsigned int> m_unassigned_layers; db::LayerMap m_layer_map; bool m_create_layers; + bool m_has_explicit_layer_mapping; int m_laynum; std::map m_default_number; + std::map m_via_cells; const LEFDEFReaderOptions *mp_tech_comp; + + std::pair open_layer_uncached (db::Layout &layout, const std::string &name, LayerPurpose purpose); }; /** @@ -595,7 +749,7 @@ public: * * This method reads the layout specified into the given layout */ - void read (tl::InputStream &stream, db::Layout &layout, LEFDEFLayerDelegate &layer_delegate); + void read (tl::InputStream &stream, db::Layout &layout, LEFDEFReaderState &state); protected: /** @@ -635,6 +789,16 @@ protected: */ 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 */ @@ -655,12 +819,30 @@ protected: */ long get_long (); + /** + * @brief Gets an orientation code + * The orientation code is read employing the LEF/DEF convention ("N" for r0 etc.) + */ + db::FTrans get_orient (bool optional); + + /** + * @brief Reads a point + * A point is given by two coordinates, x and y + */ + db::Point get_point (double scale); + + /** + * @brief Reads a vector + * A vector is given by two coordinates, x and y + */ + db::Vector get_vector (double scale); + /** * @brief Create a new layer or return the index of the given layer */ std::pair open_layer (db::Layout &layout, const std::string &name, LayerPurpose purpose) { - return mp_layer_delegate->open_layer (layout, name, purpose); + return mp_reader_state->open_layer (layout, name, purpose); } /** @@ -668,7 +850,7 @@ protected: */ void register_layer (const std::string &l) { - mp_layer_delegate->register_layer (l); + mp_reader_state->register_layer (l); } /** @@ -735,7 +917,22 @@ protected: return m_pin_prop_name_id; } -protected: + /** + * @brief Gets the reader options + */ + const db::LEFDEFReaderOptions &options () const + { + return m_options; + } + + /** + * @brief Gets the reader state object + */ + db::LEFDEFReaderState *reader_state () + { + return mp_reader_state; + } + void create_generated_via (std::vector &bottom, std::vector &cut, std::vector &top, @@ -750,7 +947,7 @@ protected: private: tl::AbsoluteProgress *mp_progress; tl::TextInputStream *mp_stream; - LEFDEFLayerDelegate *mp_layer_delegate; + LEFDEFReaderState *mp_reader_state; std::string m_cellname; std::string m_fn; std::string m_last_token; @@ -760,6 +957,7 @@ private: db::property_names_id_type m_inst_prop_name_id; bool m_produce_pin_props; db::property_names_id_type m_pin_prop_name_id; + db::LEFDEFReaderOptions m_options; const std::string &next (); }; diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFPlugin.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFPlugin.cc index d9b10b28a..2bd4466ae 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFPlugin.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFPlugin.cc @@ -30,6 +30,8 @@ #include "dbLEFImporter.h" #include "dbDEFImporter.h" #include "dbLEFDEFImporter.h" +#include "dbLayoutUtils.h" +#include "dbTechnology.h" namespace db { @@ -102,14 +104,32 @@ public: { return "LEFDEF"; } + private: tl::InputStream &m_stream; db::LayerMap m_layer_map; - std::string correct_path (const std::string &fn) + std::string correct_path (const std::string &fn, const db::Layout &layout) { if (! tl::is_absolute (fn)) { - return tl::combine_path (m_stream.absolute_path (), fn); + + // if a technology is given and the file can be found in the technology's base path, take it + // from there. + std::string tn = layout.meta_info_value ("technology"); + const db::Technology *tech = 0; + if (! tn.empty ()) { + tech = db::Technologies::instance ()->technology_by_name (tn); + } + + if (tech && ! tech->base_path ().empty ()) { + std::string new_fn = tl::combine_path (tech->base_path (), fn); + if (tl::file_exists (new_fn)) { + return new_fn; + } + } + + return tl::combine_path (tl::dirname (m_stream.absolute_path ()), fn); + } else { return fn; } @@ -123,49 +143,53 @@ private: lefdef_options = &default_options; } - // Take the layer map and the "read all layers" flag from the reader options - hence we override the - db::LEFDEFLayerDelegate layers (lefdef_options); - layers.prepare (layout); + db::LEFDEFReaderState state (lefdef_options, layout); + + if (! lefdef_options->map_file ().empty ()) { + state.read_map_file (correct_path (lefdef_options->map_file (), layout), layout); + } + layout.dbu (lefdef_options->dbu ()); if (import_lef) { - tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (tr ("Reading LEF file"))); + tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Reading LEF file"))); db::LEFImporter importer; for (std::vector::const_iterator l = lefdef_options->begin_lef_files (); l != lefdef_options->end_lef_files (); ++l) { - std::string lp = correct_path (*l); + std::string lp = correct_path (*l, layout); tl::InputStream lef_stream (lp); tl::log << tl::to_string (tr ("Reading")) << " " << lp; - importer.read (lef_stream, layout, layers); + importer.read (lef_stream, layout, state); } tl::log << tl::to_string (tr ("Reading")) << " " << m_stream.source (); - importer.read (m_stream, layout, layers); + importer.read (m_stream, layout, state); } else { - tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (tr ("Reading DEF file"))); + tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Reading DEF file"))); DEFImporter importer; for (std::vector::const_iterator l = lefdef_options->begin_lef_files (); l != lefdef_options->end_lef_files (); ++l) { - std::string lp = correct_path (*l); + std::string lp = correct_path (*l, layout); tl::InputStream lef_stream (lp); tl::log << tl::to_string (tr ("Reading")) << " " << lp; - importer.read_lef (lef_stream, layout, layers); + importer.read_lef (lef_stream, layout, state); } // Additionally read all LEF files next to the DEF file std::string input_dir = tl::absolute_path (m_stream.absolute_path ()); + if (tl::file_exists (input_dir)) { std::vector entries = tl::dir_entries (input_dir); @@ -174,9 +198,12 @@ private: if (is_lef_format (*e)) { std::string lp = tl::combine_path (input_dir, *e); + + tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Reading LEF file: ")) + lp); + tl::InputStream lef_stream (lp); tl::log << tl::to_string (tr ("Reading")) << " " << lp; - importer.read_lef (lef_stream, layout, layers); + importer.read_lef (lef_stream, layout, state); } @@ -185,17 +212,50 @@ private: } tl::log << tl::to_string (tr ("Reading")) << " " << m_stream.source (); - importer.read (m_stream, layout, layers); + importer.read (m_stream, layout, state); } - layers.finish (layout); + state.finish (layout); - m_layer_map = layers.layer_map (); + m_layer_map = state.layer_map (); return m_layer_map; } }; +namespace { + + struct MacroResolutionModeConverter + { + public: + MacroResolutionModeConverter () + { + m_values.push_back ("default"); + m_values.push_back ("always-lef"); + m_values.push_back ("always-cellref"); + } + + std::string to_string (unsigned int v) const + { + return v < m_values.size () ? m_values[v] : std::string (); + } + + void from_string (const std::string &s, unsigned int &v) const + { + v = 0; + for (unsigned int i = 0; i < (unsigned int) m_values.size (); ++i) { + if (m_values [i] == s) { + v = i; + } + } + } + + private: + std::vector m_values; + }; + +} + class LEFDEFFormatDeclaration : public db::StreamFormatDeclaration { @@ -253,6 +313,9 @@ class LEFDEFFormatDeclaration tl::make_member (&LEFDEFReaderOptions::produce_pins, &LEFDEFReaderOptions::set_produce_pins, "produce-pins") + tl::make_member (&LEFDEFReaderOptions::pins_suffix, &LEFDEFReaderOptions::set_pins_suffix, "pins-suffix") + tl::make_member (&LEFDEFReaderOptions::pins_datatype, &LEFDEFReaderOptions::set_pins_datatype, "pins-datatype") + + tl::make_member (&LEFDEFReaderOptions::produce_lef_pins, &LEFDEFReaderOptions::set_produce_lef_pins, "produce-lef-pins") + + tl::make_member (&LEFDEFReaderOptions::lef_pins_suffix, &LEFDEFReaderOptions::set_lef_pins_suffix, "lef-pins-suffix") + + tl::make_member (&LEFDEFReaderOptions::lef_pins_datatype, &LEFDEFReaderOptions::set_lef_pins_datatype, "lef-pins-datatype") + tl::make_member (&LEFDEFReaderOptions::produce_obstructions, &LEFDEFReaderOptions::set_produce_obstructions, "produce-obstructions") + tl::make_member (&LEFDEFReaderOptions::obstructions_suffix, &LEFDEFReaderOptions::set_obstructions_suffix, "obstructions-suffix") + tl::make_member (&LEFDEFReaderOptions::obstructions_datatype, &LEFDEFReaderOptions::set_obstructions_datatype, "obstructions-datatype") + @@ -265,7 +328,13 @@ class LEFDEFFormatDeclaration tl::make_member (&LEFDEFReaderOptions::produce_routing, &LEFDEFReaderOptions::set_produce_routing, "produce-routing") + tl::make_member (&LEFDEFReaderOptions::routing_suffix, &LEFDEFReaderOptions::set_routing_suffix, "routing-suffix") + tl::make_member (&LEFDEFReaderOptions::routing_datatype, &LEFDEFReaderOptions::set_routing_datatype, "routing-datatype") + - tl::make_member (&LEFDEFReaderOptions::begin_lef_files, &LEFDEFReaderOptions::end_lef_files, &LEFDEFReaderOptions::push_lef_file, "lef-files") + tl::make_member (&LEFDEFReaderOptions::produce_special_routing, &LEFDEFReaderOptions::set_produce_special_routing, "produce-special-routing") + + tl::make_member (&LEFDEFReaderOptions::special_routing_suffix, &LEFDEFReaderOptions::set_special_routing_suffix, "special-routing-suffix") + + tl::make_member (&LEFDEFReaderOptions::special_routing_datatype, &LEFDEFReaderOptions::set_special_routing_datatype, "special-routing-datatype") + + tl::make_member (&LEFDEFReaderOptions::begin_lef_files, &LEFDEFReaderOptions::end_lef_files, &LEFDEFReaderOptions::push_lef_file, "lef-files") + + tl::make_member (&LEFDEFReaderOptions::macro_resolution_mode, &LEFDEFReaderOptions::set_macro_resolution_mode, "macro-resolution-mode", MacroResolutionModeConverter ()) + + tl::make_member (&LEFDEFReaderOptions::separate_groups, &LEFDEFReaderOptions::set_separate_groups, "separate-groups") + + tl::make_member (&LEFDEFReaderOptions::map_file, &LEFDEFReaderOptions::set_map_file, "map-file") ); } }; diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc index 95506ff67..7bf3c307a 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc @@ -65,12 +65,23 @@ LEFImporter::layer_ext (const std::string &layer, double def_ext) const } } -double -LEFImporter::layer_width (const std::string &layer, const std::string &nondefaultrule, double def_width) const +std::pair +LEFImporter::min_layer_width (const std::string &layer) const { - std::map >::const_iterator nd = m_nondefault_widths.find (nondefaultrule); + std::map >::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); + } +} - std::map::const_iterator l; +std::pair +LEFImporter::layer_width (const std::string &layer, const std::string &nondefaultrule, const std::pair &def_width) const +{ + std::map > >::const_iterator nd = m_nondefault_widths.find (nondefaultrule); + + std::map >::const_iterator l; bool has_width = false; if (! nondefaultrule.empty () && nd != m_nondefault_widths.end ()) { @@ -94,14 +105,14 @@ LEFImporter::layer_width (const std::string &layer, const std::string &nondefaul } } -db::Cell * +std::pair LEFImporter::macro_by_name (const std::string &name) const { - std::map::const_iterator m = m_macros_by_name.find (name); + std::map >::const_iterator m = m_macros_by_name.find (name); if (m != m_macros_by_name.end ()) { return m->second; } else { - return 0; + return std::make_pair ((db::Cell *) 0, db::Trans ()); } } @@ -174,9 +185,9 @@ LEFImporter::read_geometries (db::Layout &layout, db::Cell &cell, LayerPurpose p } w = 0.0; - std::map::const_iterator dw = m_default_widths.find (layer_name); + std::map >::const_iterator dw = m_default_widths.find (layer_name); if (dw != m_default_widths.end ()) { - w = dw->second; + w = dw->second.first; } while (! test (";")) { @@ -334,20 +345,18 @@ LEFImporter::read_geometries (db::Layout &layout, db::Cell &cell, LayerPurpose p points.push_back (db::Vector (db::DVector (x / dbu, y / dbu))); std::string vn = get (); - std::pair cn = layout.cell_by_name (("VIA_" + vn).c_str ()); - if (! cn.first) { - warn ("Unknown via: " + vn); + db::Cell *vc = reader_state ()->via_cell (vn); + if (! vc) { + warn (tl::to_string (tr ("Unknown via: ")) + vn); } if (iterate) { std::vector ti = get_iteration (layout); - if (cn.first) { - for (std::vector::const_iterator t = ti.begin (); t != ti.end (); ++t) { - cell.insert (db::CellInstArray (db::CellInst (cn.second), *t * db::Trans (points [0]))); - } + for (std::vector::const_iterator t = ti.begin (); t != ti.end (); ++t) { + cell.insert (db::CellInstArray (db::CellInst (vc->cell_index ()), *t * db::Trans (points [0]))); } - } else if (cn.first) { - cell.insert (db::CellInstArray (db::CellInst (cn.second), db::Trans (points [0]))); + } else { + cell.insert (db::CellInstArray (db::CellInst (vc->cell_index ()), db::Trans (points [0]))); } expect (";"); @@ -360,6 +369,568 @@ 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] = std::make_pair (w, 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 > > geometry; + geometry.push_back (std::pair > ()); + geometry.push_back (std::pair > ()); + geometry.push_back (std::pair > ()); + + 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 > >::const_iterator g = geometry.begin (); g != geometry.end (); ++g) { + std::pair dl = open_layer (layout, g->first, ViaGeometry); + if (dl.first) { + for (std::vector::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 bboxes; + read_geometries (layout, cell, ViaGeometry, &bboxes); + + // determine m1 and m2 layers + + std::vector routing_layers; + for (std::map::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 (tl::to_string (tr ("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 = options ().via_cellname_prefix () + n; + db::Cell &cell = layout.cell (layout.add_cell (cellname.c_str ())); + reader_state ()->register_via_cell (n, &cell); + + 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; + double w = 0.0, w_wrongdir = 0.0; + bool is_horizontal = false; + + 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")) { + + std::string type = get (); + + if (type == "ROUTING" || type == "MASTERSLICE") { + m_routing_layers.insert (ln); + } else if (type == "CUT") { + m_cut_layers.insert (ln); + } + expect (";"); + + } else if (test ("WIDTH")) { + + w = get_double (); + expect (";"); + + } else if (test ("MINWIDTH")) { + + wmin = get_double (); + expect (";"); + + } else if (test ("DIRECTION")) { + + if (test ("HORIZONTAL")) { + is_horizontal = true; + } else { + expect ("VERTICAL", "DIAG45", "DIAG135"); + } + + } else if (test ("WIREEXTENSION")) { + + double v = get_double (); + m_default_ext.insert (std::make_pair (ln, v)); + 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 v = 0.0; + if (ex.test ("MINWIDTH") && ex.try_read (v)) { + if (ex.test ("WRONGDIRECTION")) { + wmin_wrongdir = v; + } else { + 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 (";")) { + take (); + } + + } + } + + 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 (wmin_wrongdir == 0.0) { + wmin_wrongdir = wmin; + } else 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 (); + + if (m_macros_by_name.find (mn) != m_macros_by_name.end ()) { + error (tl::to_string (tr ("Duplicate MACRO name: ")) + mn); + } + + set_cellname (mn); + + db::Cell &cell = layout.cell (layout.add_cell ()); + db::Cell *foreign_cell = 0; + db::Trans foreign_trans; + std::string foreign_name; + + db::Point origin; + db::Vector size; + + // read the macro + while (! at_end ()) { + + if (test ("END")) { + expect (mn); + break; + + } else if (test ("ORIGIN")) { + + origin = get_point (1.0 / layout.dbu ()); + expect (";"); + + } 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 bboxes; + read_geometries (layout, cell, LEFPins, &bboxes, prop_id); + + for (std::map ::const_iterator b = bboxes.begin (); b != bboxes.end (); ++b) { + std::pair 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 ("FOREIGN")) { + + if (foreign_cell) { + error (tl::to_string (tr ("Duplicate FOREIGN definition"))); + } + + std::string cn = get (); + + db::Point vec; + db::FTrans ft; + if (! peek (";")) { + vec = get_point (1.0 / layout.dbu ()); + ft = get_orient (true); + } + + expect (";"); + + if (options ().macro_resolution_mode () != 1) { + + db::cell_index_type ci; + std::pair c = layout.cell_by_name (cn.c_str ()); + if (c.first) { + ci = c.second; + } else { + ci = layout.add_cell (cn.c_str ()); + layout.cell (ci).set_ghost_cell (true); + } + + foreign_cell = &layout.cell (ci); + // What is the definition of the FOREIGN transformation? + // Guessing: this transformation moves the lower-left origin to 0,0 + foreign_trans = db::Trans (db::Point () - vec) * db::Trans (ft); + foreign_name = cn; + + } + + } else if (test ("OBS")) { + + read_geometries (layout, cell, Obstructions); + expect ("END"); + + } else { + while (! test (";")) { + take (); + } + } + + } + + if (! foreign_cell) { + + if (options ().macro_resolution_mode () != 2) { + + // actually implement the real cell + + layout.rename_cell (cell.cell_index (), mn.c_str ()); + + std::pair dl = open_layer (layout, std::string (), Outline); + if (dl.first) { + cell.shapes (dl.second).insert (db::Box (-origin, -origin + size)); + } + + m_macros_by_name.insert (std::make_pair (mn, std::make_pair (&cell, db::Trans ()))); + + } else { + + // macro resolution mode #2 (always create a MACRO reference, no LEF geometry) + + db::cell_index_type ci; + std::pair c = layout.cell_by_name (mn.c_str ()); + if (c.first) { + ci = c.second; + } else { + ci = layout.add_cell (mn.c_str ()); + layout.cell (ci).set_ghost_cell (true); + } + + layout.delete_cell (cell.cell_index ()); + m_macros_by_name.insert (std::make_pair (mn, std::make_pair (&layout.cell (ci), db::Trans ()))); + + } + + } else if (foreign_name != mn) { + + warn (tl::to_string (tr ("FOREIGN name differs from MACRO name in macro: ")) + mn); + + layout.rename_cell (cell.cell_index (), mn.c_str ()); + + // clear imported LEF geometry with a foreign cell, but provide a level of indirection so we have + // both the MACRO and the FOREIGN name + + for (unsigned int l = 0; l < layout.layers (); ++l) { + if (layout.is_valid_layer (l)) { + cell.clear (l); + } + } + + cell.clear_insts (); + + cell.insert (db::CellInstArray (db::CellInst (foreign_cell->cell_index ()), db::Trans (db::Point () - origin) * foreign_trans)); + m_macros_by_name.insert (std::make_pair (mn, std::make_pair (&cell, db::Trans ()))); + + } else { + + // use FOREIGN cell instead of new one + + layout.delete_cell (cell.cell_index ()); + m_macros_by_name.insert (std::make_pair (mn, std::make_pair (foreign_cell, db::Trans (db::Point () - origin) * foreign_trans))); + + } + + m_macro_bboxes_by_name.insert (std::make_pair (mn, db::Box (-origin, -origin + size))); + + reset_cellname (); +} + void LEFImporter::do_read (db::Layout &layout) { @@ -414,45 +985,7 @@ LEFImporter::do_read (db::Layout &layout) } else if (test ("NONDEFAULTRULE")) { - // 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 (); - } - } - - } + read_nondefaultrule (layout); } else if (test ("SITE")) { @@ -472,146 +1005,7 @@ LEFImporter::do_read (db::Layout &layout) } else if (test ("VIA")) { - 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")) { - - 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 > > geometry; - geometry.push_back (std::pair > ()); - geometry.push_back (std::pair > ()); - geometry.push_back (std::pair > ()); - - 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 > >::const_iterator g = geometry.begin (); g != geometry.end (); ++g) { - std::pair dl = open_layer (layout, g->first, ViaGeometry); - if (dl.first) { - for (std::vector::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 (";"); - } - - read_geometries (layout, cell, ViaGeometry); - - reset_cellname (); - - expect ("END"); - - } - - test ("VIA"); - expect (n); + read_viadef (layout); } else if (test ("BEGINEXT")) { @@ -622,148 +1016,11 @@ LEFImporter::do_read (db::Layout &layout) } else if (test ("LAYER")) { - std::string ln = get (); - - 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 ("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 (); - } - } - } + read_layer (layout); } else if (test ("MACRO")) { - 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 bboxes; - read_geometries (layout, cell, Pins, &bboxes, prop_id); - - for (std::map ::const_iterator b = bboxes.begin (); b != bboxes.end (); ++b) { - std::pair 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 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 (); + read_macro (layout); } else { while (! test (";")) { diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.h b/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.h index 9811d9bfc..859ceef54 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.h +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.h @@ -63,7 +63,7 @@ public: * Returns 0 if the name is not a valid macro name. Otherwise it returns the pointer * to the corresponding db::Cell object. */ - db::Cell *macro_by_name (const std::string ¯o_name) const; + std::pair macro_by_name (const std::string ¯o_name) const; /** * @brief Get the cell bbox for the given macro name @@ -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 layer_width (const std::string &layer, const std::string &nondefaultrule, const std::pair &def_width = std::make_pair (0.0, 0.0)) const; /** * @brief Get the extension for a layer with the given name @@ -86,6 +86,27 @@ public: */ 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 min_layer_width (const std::string &layer) const; + + /** + * @brief Returns true if the given layer is a routing layer + */ + bool is_routing_layer (const std::string &layer) const + { + return m_routing_layers.find (layer) != m_routing_layers.end (); + } + + /** + * @brief Returns true if the given layer is a cut layer + */ + bool is_cut_layer (const std::string &layer) const + { + return m_cut_layers.find (layer) != m_cut_layers.end (); + } + /** * @brief Gets a map of the vias defined in this LEF file * @@ -100,15 +121,23 @@ protected: void do_read (db::Layout &layout); private: - std::map > m_nondefault_widths; - std::map m_default_widths; + std::map > > m_nondefault_widths; + std::map > m_default_widths; std::map m_default_ext; - std::map m_macros_by_name; + std::map > m_min_widths; + std::map > m_macros_by_name; std::map m_macro_bboxes_by_name; std::map m_vias; + std::set m_routing_layers, m_cut_layers; std::vector get_iteration (db::Layout &layout); void read_geometries (db::Layout &layout, db::Cell &cell, LayerPurpose purpose, std::map *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); }; } diff --git a/src/plugins/streamers/lefdef/db_plugin/gsiDeclDbLEFDEF.cc b/src/plugins/streamers/lefdef/db_plugin/gsiDeclDbLEFDEF.cc index f0640f3e4..8c4fc324b 100644 --- a/src/plugins/streamers/lefdef/db_plugin/gsiDeclDbLEFDEF.cc +++ b/src/plugins/streamers/lefdef/db_plugin/gsiDeclDbLEFDEF.cc @@ -260,6 +260,18 @@ gsi::Class decl_lefdef_config ("db", "LEFDEFReaderConfi "@brief Sets the via geometry layer datatype value.\n" "See \\produce_via_geometry for details about this property.\n" ) + + gsi::method ("via_cellname_prefix", &db::LEFDEFReaderOptions::via_cellname_prefix, + "@brief Gets the via cellname prefix.\n" + "Vias are represented by cells. The cell name is formed by combining the via cell name prefix and the via name.\n" + "\n" + "This property has been added in version 0.27.\n" + ) + + gsi::method ("via_cellname_prefix=", &db::LEFDEFReaderOptions::set_via_cellname_prefix, gsi::arg ("prefix"), + "@brief Sets the via cellname prefix.\n" + "See \\via_cellname_prefix for details about this property.\n" + "\n" + "This property has been added in version 0.27.\n" + ) + gsi::method ("produce_pins", &db::LEFDEFReaderOptions::produce_pins, "@brief Gets a value indicating whether pin geometries shall be produced.\n" "See \\produce_via_geometry for details about the layer production rules." @@ -284,6 +296,30 @@ gsi::Class decl_lefdef_config ("db", "LEFDEFReaderConfi "@brief Sets the pin geometry layer datatype value.\n" "See \\produce_via_geometry for details about the layer production rules." ) + + gsi::method ("produce_lef_pins", &db::LEFDEFReaderOptions::produce_lef_pins, + "@brief Gets a value indicating whether LEF pin geometries shall be produced.\n" + "See \\produce_via_geometry for details about the layer production rules." + ) + + gsi::method ("produce_lef_pins=", &db::LEFDEFReaderOptions::set_produce_lef_pins, gsi::arg ("produce"), + "@brief Sets a value indicating whether LEF pin geometries shall be produced.\n" + "See \\produce_via_geometry for details about the layer production rules." + ) + + gsi::method ("lef_pins_suffix", &db::LEFDEFReaderOptions::lef_pins_suffix, + "@brief Gets the LEF pin geometry layer name suffix.\n" + "See \\produce_via_geometry for details about the layer production rules." + ) + + gsi::method ("lef_pins_suffix=", &db::LEFDEFReaderOptions::set_lef_pins_suffix, gsi::arg ("suffix"), + "@brief Sets the LEF pin geometry layer name suffix.\n" + "See \\produce_via_geometry for details about the layer production rules." + ) + + gsi::method ("lef_pins_datatype", &db::LEFDEFReaderOptions::lef_pins_datatype, + "@brief Gets the LEF pin geometry layer datatype value.\n" + "See \\produce_via_geometry for details about the layer production rules." + ) + + gsi::method ("lef_pins_datatype=", &db::LEFDEFReaderOptions::set_lef_pins_datatype, gsi::arg ("datatype"), + "@brief Sets the LEF pin geometry layer datatype value.\n" + "See \\produce_via_geometry for details about the layer production rules." + ) + gsi::method ("produce_obstructions", &db::LEFDEFReaderOptions::produce_obstructions, "@brief Gets a value indicating whether obstruction markers shall be produced.\n" "See \\produce_via_geometry for details about the layer production rules." @@ -380,6 +416,92 @@ gsi::Class decl_lefdef_config ("db", "LEFDEFReaderConfi "@brief Sets the routing layer datatype value.\n" "See \\produce_via_geometry for details about the layer production rules." ) + + gsi::method ("produce_special_routing", &db::LEFDEFReaderOptions::produce_special_routing, + "@brief Gets a value indicating whether special routing geometry shall be produced.\n" + "See \\produce_via_geometry for details about the layer production rules.\n" + "\n" + "The differentiation between special and normal routing has been introduced in version 0.27." + ) + + gsi::method ("produce_special_routing=", &db::LEFDEFReaderOptions::set_produce_special_routing, gsi::arg ("produce"), + "@brief Sets a value indicating whether special routing geometry shall be produced.\n" + "See \\produce_via_geometry for details about the layer production rules." + "\n" + "The differentiation between special and normal routing has been introduced in version 0.27." + ) + + gsi::method ("special_routing_suffix", &db::LEFDEFReaderOptions::special_routing_suffix, + "@brief Gets the special routing layer name suffix.\n" + "See \\produce_via_geometry for details about the layer production rules." + "\n" + "The differentiation between special and normal routing has been introduced in version 0.27." + ) + + gsi::method ("special_routing_suffix=", &db::LEFDEFReaderOptions::set_special_routing_suffix, gsi::arg ("suffix"), + "@brief Sets the special routing layer name suffix.\n" + "See \\produce_via_geometry for details about the layer production rules." + "\n" + "The differentiation between special and normal routing has been introduced in version 0.27." + ) + + gsi::method ("special_routing_datatype", &db::LEFDEFReaderOptions::special_routing_datatype, + "@brief Gets the special routing layer datatype value.\n" + "See \\produce_via_geometry for details about the layer production rules." + "\n" + "The differentiation between special and normal routing has been introduced in version 0.27." + ) + + gsi::method ("special_routing_datatype=", &db::LEFDEFReaderOptions::set_special_routing_datatype, gsi::arg ("datatype"), + "@brief Sets the special routing layer datatype value.\n" + "See \\produce_via_geometry for details about the layer production rules." + "\n" + "The differentiation between special and normal routing has been introduced in version 0.27." + ) + + gsi::method ("separate_groups", &db::LEFDEFReaderOptions::separate_groups, + "@brief Gets a value indicating whether to create separate parent cells for individual groups.\n" + "If this property is set to true, instances belonging to different groups are separated by putting them into " + "individual parent cells. These parent cells are named after the groups and are put into the master top cell.\n" + "If this property is set to false (the default), no such group parents will be formed." + "\n" + "This property has been added in version 0.27.\n" + ) + + gsi::method ("separate_groups=", &db::LEFDEFReaderOptions::set_separate_groups, gsi::arg ("flag"), + "@brief Sets a value indicating whether to create separate parent cells for individual groups.\n" + "See \\seperate_groups for details about this property.\n" + "\n" + "This property has been added in version 0.27.\n" + ) + + gsi::method ("map_file", &db::LEFDEFReaderOptions::map_file, + "@brief Gets the layer map file to use.\n" + "If a layer map file is given, the reader will pull the layer mapping from this file. The layer mapping rules " + "specified in the reader options are ignored in this case. These are the name suffix rules for vias, blockages, routing, " + "special routing, pins etc. and the corresponding datatype rules. The \\layer_map attribute will also be ignored. " + "\n" + "The layer map file path will be resolved relative to the technology base path if the LEF/DEF reader options are " + "used in the context of a technology.\n" + "\n" + "This property has been added in version 0.27.\n" + ) + + gsi::method ("map_file=", &db::LEFDEFReaderOptions::set_map_file, gsi::arg ("file"), + "@brief Sets the layer map file to use.\n" + "See \\map_file for details about this property.\n" + "\n" + "This property has been added in version 0.27.\n" + ) + + gsi::method ("macro_resolution_mode", &db::LEFDEFReaderOptions::macro_resolution_mode, + "@brief Gets the macro resolution mode.\n" + "This property describes the way LEF macros are turned into GDS cells. There " + "are three modes available:\n" + "\n" + "@ul\n" + " @li 0: propduce LEF geometry unless a FOREIGN cell is specified (default) @/li\n" + " @li 1: produce LEF geometry always and ignore FOREIGN @/li\n" + " @li 2: produce a placeholder cell always (even if FOREIGN isn't given) @/li\n" + "@/ul\n" + "\n" + "This property has been added in version 0.27.\n" + ) + + gsi::method ("macro_resolution_mode=", &db::LEFDEFReaderOptions::set_macro_resolution_mode, gsi::arg ("mode"), + "@brief Sets the macro resolution mode.\n" + "See \\macro_resolution_mode for details about this property.\n" + "\n" + "This property has been added in version 0.27.\n" + ) + gsi::method ("lef_files", &db::LEFDEFReaderOptions::lef_files, "@brief Gets the list technology LEF files to additionally import\n" "Returns a list of path names for technology LEF files to read in addition to the primary file. " @@ -394,6 +516,21 @@ gsi::Class decl_lefdef_config ("db", "LEFDEFReaderConfi "@brief Detailed LEF/DEF reader options\n" "This class is a aggregate belonging to the \\LoadLayoutOptions class. It provides options for the LEF/DEF reader. " "These options have been placed into a separate class to account for their complexity." + "\n" + "This class specifically handles layer mapping. This is the process of generating layer names or GDS layer/datatypes " + "from LEF/DEF layers and purpose combinations. There are basically two ways: to use a map file or to use pattern-based production rules.\n" + "\n" + "To use a layer map file, set the \\map_file attribute to the name of the layer map file. The layer map " + "file lists the GDS layer and datatype numbers to generate for the geometry.\n" + "\n" + "The pattern-based approach will use the layer name and attach a purpose-dependent suffix to it. " + "Use the ..._suffix attributes to specify this suffix. For routing, the corresponding attribute is \\routing_suffix for example. " + "A purpose can also be mapped to a specific GDS datatype using the corresponding ..._datatype attributes.\n" + "The decorated or undecorated names are looked up in a layer mapping table in the next step. The layer mapping table " + "is specified using the \\layer_map attribute. This table can be used to map layer names to specific GDS layers " + "by using entries of the form 'NAME: layer-number'.\n" + "\n" + "If a layer map file is present, the pattern-based attributes are ignored.\n" ); } diff --git a/src/plugins/streamers/lefdef/lay_plugin/LEFDEFTechnologyComponentEditor.ui b/src/plugins/streamers/lefdef/lay_plugin/LEFDEFTechnologyComponentEditor.ui index 2b2dcf365..3b849c53f 100644 --- a/src/plugins/streamers/lefdef/lay_plugin/LEFDEFTechnologyComponentEditor.ui +++ b/src/plugins/streamers/lefdef/lay_plugin/LEFDEFTechnologyComponentEditor.ui @@ -6,8 +6,8 @@ 0 0 - 775 - 766 + 859 + 868 @@ -200,31 +200,101 @@ true - + 4 4 - - + + - Layout database unit + FOREIGN macros - + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Via cell name prefix + + + + + + + Layout DBU + + + + + + + + Link to external cells for FOREIGN, LEF macros otherwise + + + + + Ignore FOREIGN, Produce LEF macros always + + + + + Always link to external cells + + + + + + + + Produce a parent cell for each group + + + + + + + Groups + + + + - + 0 0 - + + + + + 0 + 0 + + + + + @@ -237,13 +307,29 @@ + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 5 + 20 + + + + - Production (specify what objects to produce and on what layers) + Global Production Rules (specify what objects to produce and on what layers) true @@ -264,32 +350,6 @@ 6 - - - - - 0 - 0 - - - - - - - :/right.png - - - - - - - As properties with name ... - - - - - - @@ -320,18 +380,77 @@ - - + + - Produce ... - - - Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + As properties with name ... - - + + + + + + + Qt::Vertical + + + + + + + + + + + + + :/right.png + + + + + + + + + + <html><body>(<a href="int:/about/variant_notation.xml">See here for the name notation</a>)</body></html> + + + Qt::AlignRight|Qt::AlignTop|Qt::AlignTrailing + + + + + + + + + + + + + :/right.png + + + + + + + + + + + + + :/right.png + + + + + 0 @@ -339,11 +458,11 @@ - Cell outlines + Blockages - + @@ -374,9 +493,6 @@ - - - @@ -384,63 +500,7 @@ - - - - - 0 - 0 - - - - Blockages - - - - - - - <html><body>(<a href="int:/about/variant_notation.xml">See here for the name notation</a>)</body></html> - - - Qt::AlignRight|Qt::AlignTop|Qt::AlignTrailing - - - - - - - - - - GDS datatype ... - - - - - - Layer name suffix ... - - - - - - - - 0 - 0 - - - - - - - :/right.png - - - - On layer with spec ... @@ -450,95 +510,59 @@ - - - - - - - - + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + Produce ... + + + + + - + - - - - Via geometry - - - - - - - - - - :/right.png - - - - - - - Qt::Vertical - - - - - - - Produce ... - - - - - - - Pins - - - - + - - Regions - - - - - - + 0 0 - - - - :/right.png + Regions - - - - - - - :/right.png - - - - - - - - - @@ -546,28 +570,21 @@ - - - - + + + + + 0 + 0 + - - :/right.png + + Cell outlines - - - - - - - Obstructions - - - - - + + 0 @@ -582,169 +599,426 @@ - - - - - - - - - - Routing - - - - - - - - 0 - 0 - - - - - - - :/right.png - - - - - - - - - - - - - Pin labels - - - - - - - Blockages - - - - - - - - 0 - 0 - - - - - - - :/right.png - - - - - - - - 0 - 0 - - - - - - - :/right.png - - - - - - - - - - - - - - - - - - - 0 - 1 - + + + 0 - - Layer Mapping (filter/modify layers, assign GDS layer/datatypes) - - - true - - - - 6 - - - 9 - - - 4 - - - 9 - - - 4 - - - - - Read all layers (additionally to the ones in the mapping table) - - - - - - - Qt::Horizontal - - - - - - - - 0 - 1 - - - - - 16 - 0 - - - - QFrame::NoFrame - - - QFrame::Raised - - - - + + + Layer Map File + + + + + + Qt::Vertical + + + + 20 + 278 + + + + + + + + Layer map file + + + + + + + ... + + + false + + + + + + + + + + If a layer map file is given, pattern based rules are ignored. +If used inside a technology, the file will be looked up relative to the technology's base path. + + + + + + + + Pattern Based Layer Production Rules + + + + + + + 0 + 150 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + 0 + 0 + + + + + + + :/right.png + + + + + + + + + + + + + Special routing + + + + + + + + + + + + + + + + + 0 + 0 + + + + + + + :/right.png + + + + + + + + + + + + + + + + + 0 + 0 + + + + + + + :/right.png + + + + + + + + 0 + 0 + + + + + + + :/right.png + + + + + + + Routing + + + + + + + + + + + 0 + 0 + + + + + + + :/right.png + + + + + + + + 0 + 0 + + + + + + + :/right.png + + + + + + + Via geometry + + + + + + + Pin labels + + + + + + + LEF Pins + + + + + + + Layer name suffix ... + + + + + + + Pins + + + + + + + + + + + + + GDS datatype ... + + + + + + + + 0 + 0 + + + + + + + :/right.png + + + + + + + + + + + + + + + + Blockages + + + + + + + Obstructions + + + + + + + + 0 + 0 + + + + + + + :/right.png + + + + + + + + + + Layer name suffix ... + + + + + + + GDS datatype ... + + + + + + + Qt::Vertical + + + + + + + + + + + 0 + 1 + + + + Layer Mapping (filter/modify layers, assign GDS layer/datatypes) + + + true + + + + 9 + + + 4 + + + 9 + + + 4 + + + + + Read all layers (additionally to the ones in the mapping table) + + + + + + + + 0 + 1 + + + + + 16 + 0 + + + + QFrame::NoFrame + + + QFrame::Raised + + + + + + + Qt::Horizontal + + + + + + + + @@ -769,16 +1043,6 @@ dbu produce_net_names net_prop_name - produce_outlines - outline_layer - produce_placement_blockages - placement_blockage_layer - produce_via_geometry - suffix_via_geometry - datatype_via_geometry - produce_pins - suffix_pins - datatype_pins read_all_cbx @@ -792,12 +1056,12 @@ setChecked(bool) - 186 - 598 + 229 + 838 - 155 - 553 + 198 + 701 diff --git a/src/plugins/streamers/lefdef/lay_plugin/layLEFDEFImport.cc b/src/plugins/streamers/lefdef/lay_plugin/layLEFDEFImport.cc index 3c8f051c2..f16b275ef 100644 --- a/src/plugins/streamers/lefdef/lay_plugin/layLEFDEFImport.cc +++ b/src/plugins/streamers/lefdef/lay_plugin/layLEFDEFImport.cc @@ -140,8 +140,7 @@ public: } } - db::LEFDEFLayerDelegate layers (&options); - layers.prepare (*layout); + db::LEFDEFReaderState state (&options, *layout); layout->dbu (options.dbu ()); if (import_lef) { @@ -153,11 +152,11 @@ public: for (std::vector::const_iterator l = options.begin_lef_files (); l != options.end_lef_files (); ++l) { tl::InputStream lef_stream (*l); tl::log << tl::to_string (QObject::tr ("Reading")) << " " << *l; - importer.read (lef_stream, *layout, layers); + importer.read (lef_stream, *layout, state); } tl::log << tl::to_string (QObject::tr ("Reading")) << " " << data.file; - importer.read (stream, *layout, layers); + importer.read (stream, *layout, state); } else { @@ -177,23 +176,23 @@ public: if (fi.isAbsolute ()) { tl::InputStream lef_stream (*l); tl::log << tl::to_string (QObject::tr ("Reading")) << " " << *l; - importer.read_lef (lef_stream, *layout, layers); + importer.read_lef (lef_stream, *layout, state); } else { std::string ex_l = tl::to_string (def_fi.absoluteDir ().absoluteFilePath (tl::to_qstring (*l))); tl::InputStream lef_stream (ex_l); tl::log << tl::to_string (QObject::tr ("Reading")) << " " << *l; - importer.read_lef (lef_stream, *layout, layers); + importer.read_lef (lef_stream, *layout, state); } } tl::log << tl::to_string (QObject::tr ("Reading")) << " " << data.file; - importer.read (stream, *layout, layers); + importer.read (stream, *layout, state); } - layers.finish (*layout); + state.finish (*layout); lay::LayoutView *view = lay::LayoutView::current (); if (! view || data.mode == 1) { diff --git a/src/plugins/streamers/lefdef/lay_plugin/layLEFDEFImportDialogs.cc b/src/plugins/streamers/lefdef/lay_plugin/layLEFDEFImportDialogs.cc index 14474fa23..2ca27a3d8 100644 --- a/src/plugins/streamers/lefdef/lay_plugin/layLEFDEFImportDialogs.cc +++ b/src/plugins/streamers/lefdef/lay_plugin/layLEFDEFImportDialogs.cc @@ -353,14 +353,17 @@ LEFDEFReaderOptionsEditor::LEFDEFReaderOptionsEditor (QWidget *parent) connect (produce_regions, SIGNAL (stateChanged (int)), this, SLOT (checkbox_changed ())); connect (produce_via_geometry, SIGNAL (stateChanged (int)), this, SLOT (checkbox_changed ())); connect (produce_pins, SIGNAL (stateChanged (int)), this, SLOT (checkbox_changed ())); + connect (produce_lef_pins, SIGNAL (stateChanged (int)), this, SLOT (checkbox_changed ())); connect (produce_obstructions, SIGNAL (stateChanged (int)), this, SLOT (checkbox_changed ())); connect (produce_blockages, SIGNAL (stateChanged (int)), this, SLOT (checkbox_changed ())); connect (produce_routing, SIGNAL (stateChanged (int)), this, SLOT (checkbox_changed ())); + connect (produce_special_routing, SIGNAL (stateChanged (int)), this, SLOT (checkbox_changed ())); connect (produce_labels, SIGNAL (stateChanged (int)), this, SLOT (checkbox_changed ())); connect (add_lef_file, SIGNAL (clicked ()), this, SLOT (add_lef_file_clicked ())); connect (del_lef_files, SIGNAL (clicked ()), this, SLOT (del_lef_files_clicked ())); connect (move_lef_files_up, SIGNAL (clicked ()), this, SLOT (move_lef_files_up_clicked ())); connect (move_lef_files_down, SIGNAL (clicked ()), this, SLOT (move_lef_files_down_clicked ())); + connect (browse_mapfile, SIGNAL (clicked ()), this, SLOT (browse_mapfile_clicked ())); lay::activate_help_links (help_label); } @@ -425,9 +428,13 @@ LEFDEFReaderOptionsEditor::commit (db::FormatSpecificReaderOptions *options, con data->set_produce_via_geometry (produce_via_geometry->isChecked ()); data->set_via_geometry_suffix (tl::to_string (suffix_via_geometry->text ())); data->set_via_geometry_datatype (datatype_via_geometry->text ().toInt ()); + data->set_via_cellname_prefix (tl::to_string (prefix_via_cellname->text ())); data->set_produce_pins (produce_pins->isChecked ()); data->set_pins_suffix (tl::to_string (suffix_pins->text ())); data->set_pins_datatype (datatype_pins->text ().toInt ()); + data->set_produce_lef_pins (produce_lef_pins->isChecked ()); + data->set_lef_pins_suffix (tl::to_string (suffix_lef_pins->text ())); + data->set_lef_pins_datatype (datatype_lef_pins->text ().toInt ()); data->set_produce_obstructions (produce_obstructions->isChecked ()); data->set_obstructions_suffix (tl::to_string (suffix_obstructions->text ())); data->set_obstructions_datatype (datatype_obstructions->text ().toInt ()); @@ -437,9 +444,15 @@ LEFDEFReaderOptionsEditor::commit (db::FormatSpecificReaderOptions *options, con data->set_produce_routing (produce_routing->isChecked ()); data->set_routing_suffix (tl::to_string (suffix_routing->text ())); data->set_routing_datatype (datatype_routing->text ().toInt ()); + data->set_produce_special_routing (produce_special_routing->isChecked ()); + data->set_special_routing_suffix (tl::to_string (suffix_special_routing->text ())); + data->set_special_routing_datatype (datatype_special_routing->text ().toInt ()); data->set_produce_labels (produce_labels->isChecked ()); data->set_labels_suffix (tl::to_string (suffix_labels->text ())); data->set_labels_datatype (datatype_labels->text ().toInt ()); + data->set_separate_groups (separate_groups->isChecked ()); + data->set_map_file (tl::to_string (mapfile_path->text ())); + data->set_macro_resolution_mode (foreign_mode->currentIndex ()); data->clear_lef_files (); for (int i = 0; i < lef_files->count (); ++i) { @@ -477,9 +490,13 @@ LEFDEFReaderOptionsEditor::setup (const db::FormatSpecificReaderOptions *options produce_via_geometry->setChecked (data->produce_via_geometry ()); suffix_via_geometry->setText (tl::to_qstring (data->via_geometry_suffix ())); datatype_via_geometry->setText (QString::number (data->via_geometry_datatype ())); + prefix_via_cellname->setText (tl::to_qstring (data->via_cellname_prefix ())); produce_pins->setChecked (data->produce_pins ()); suffix_pins->setText (tl::to_qstring (data->pins_suffix ())); datatype_pins->setText (QString::number (data->pins_datatype ())); + produce_lef_pins->setChecked (data->produce_lef_pins ()); + suffix_lef_pins->setText (tl::to_qstring (data->lef_pins_suffix ())); + datatype_lef_pins->setText (QString::number (data->lef_pins_datatype ())); produce_obstructions->setChecked (data->produce_obstructions ()); suffix_obstructions->setText (tl::to_qstring (data->obstructions_suffix ())); datatype_obstructions->setText (QString::number (data->obstructions_datatype ())); @@ -489,9 +506,16 @@ LEFDEFReaderOptionsEditor::setup (const db::FormatSpecificReaderOptions *options produce_routing->setChecked (data->produce_routing ()); suffix_routing->setText (tl::to_qstring (data->routing_suffix ())); datatype_routing->setText (QString::number (data->routing_datatype ())); + produce_special_routing->setChecked (data->produce_special_routing ()); + suffix_special_routing->setText (tl::to_qstring (data->special_routing_suffix ())); + datatype_special_routing->setText (QString::number (data->special_routing_datatype ())); produce_labels->setChecked (data->produce_labels ()); suffix_labels->setText (tl::to_qstring (data->labels_suffix ())); datatype_labels->setText (QString::number (data->labels_datatype ())); + separate_groups->setChecked (data->separate_groups ()); + mapfile_path->setText (tl::to_qstring (data->map_file ())); + layer_map_mode->setCurrentIndex (data->map_file ().empty () ? 1 : 0); + foreign_mode->setCurrentIndex (data->macro_resolution_mode ()); checkbox_changed (); @@ -519,25 +543,51 @@ LEFDEFReaderOptionsEditor::checkbox_changed () placement_blockage_layer->setEnabled (produce_placement_blockages->isChecked ()); suffix_via_geometry->setEnabled (produce_via_geometry->isChecked ()); suffix_pins->setEnabled (produce_pins->isChecked ()); + suffix_lef_pins->setEnabled (produce_lef_pins->isChecked ()); suffix_obstructions->setEnabled (produce_obstructions->isChecked ()); suffix_blockages->setEnabled (produce_blockages->isChecked ()); suffix_routing->setEnabled (produce_routing->isChecked ()); + suffix_special_routing->setEnabled (produce_special_routing->isChecked ()); suffix_labels->setEnabled (produce_labels->isChecked ()); datatype_via_geometry->setEnabled (produce_via_geometry->isChecked ()); datatype_pins->setEnabled (produce_pins->isChecked ()); + datatype_lef_pins->setEnabled (produce_lef_pins->isChecked ()); datatype_obstructions->setEnabled (produce_obstructions->isChecked ()); datatype_blockages->setEnabled (produce_blockages->isChecked ()); datatype_routing->setEnabled (produce_routing->isChecked ()); + datatype_special_routing->setEnabled (produce_special_routing->isChecked ()); datatype_labels->setEnabled (produce_labels->isChecked ()); } +void +LEFDEFReaderOptionsEditor::browse_mapfile_clicked () +{ + std::string title, filters; + title = tl::to_string (QObject::tr ("Select Layer Map File")); + filters = tl::to_string (QObject::tr ("LEF/DEF layer map files (*.map);;All files (*)")); + QString file = QFileDialog::getOpenFileName (this, tl::to_qstring (title), QString (), tl::to_qstring (filters)); + if (! file.isNull ()) { + if (mp_tech) { + mapfile_path->setText (tl::to_qstring (mp_tech->correct_path (tl::to_string (file)))); + } else { + mapfile_path->setText (file); + } + } +} + void LEFDEFReaderOptionsEditor::add_lef_file_clicked () { std::string title, filters; title = tl::to_string (QObject::tr ("Add LEF Files")); filters = tl::to_string (QObject::tr ("LEF files (*.lef *.LEF *.lef.gz *.LEF.gz);;All files (*)")); - QStringList files = QFileDialog::getOpenFileNames (this, tl::to_qstring (title), QString (), tl::to_qstring (filters)); + + std::string dir; + if (mp_tech) { + dir = mp_tech->base_path (); + } + + QStringList files = QFileDialog::getOpenFileNames (this, tl::to_qstring (title), tl::to_qstring (dir), tl::to_qstring (filters)); for (QStringList::const_iterator f = files.begin (); f != files.end (); ++f) { if (mp_tech) { lef_files->addItem (tl::to_qstring (mp_tech->correct_path (tl::to_string (*f)))); diff --git a/src/plugins/streamers/lefdef/lay_plugin/layLEFDEFImportDialogs.h b/src/plugins/streamers/lefdef/lay_plugin/layLEFDEFImportDialogs.h index 7234c76aa..695285e0b 100644 --- a/src/plugins/streamers/lefdef/lay_plugin/layLEFDEFImportDialogs.h +++ b/src/plugins/streamers/lefdef/lay_plugin/layLEFDEFImportDialogs.h @@ -98,6 +98,7 @@ private slots: void del_lef_files_clicked (); void move_lef_files_up_clicked (); void move_lef_files_down_clicked (); + void browse_mapfile_clicked (); private: tl::weak_ptr mp_tech; diff --git a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImport.cc b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc similarity index 57% rename from src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImport.cc rename to src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc index 367802008..827377a2a 100644 --- a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImport.cc +++ b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc @@ -49,28 +49,35 @@ static db::LEFDEFReaderOptions default_options () return tc; } -static void run_test (tl::TestBase *_this, const char *lef_dir, const char *filename, const char *au, const db::LEFDEFReaderOptions &tc, bool priv = true) +static void run_test (tl::TestBase *_this, const char *lef_dir, const char *filename, const char *au, const db::LEFDEFReaderOptions &options, bool priv = true) { - db::LEFDEFLayerDelegate ld (&tc); + std::string fn_path (priv ? tl::testsrc_private () : tl::testsrc ()); + fn_path += "/testdata/lefdef/"; + fn_path += lef_dir; + fn_path += "/"; db::Manager m (false); db::Layout layout (&m), layout2 (&m), layout_au (&m); tl::Extractor ex (filename); - ld.prepare (layout); + db::LEFDEFReaderState ld (&options, layout); db::DEFImporter imp; while (! ex.at_end ()) { - if (ex.test ("def:")) { + if (ex.test ("map:")) { - std::string fn (priv ? tl::testsrc_private () : tl::testsrc ()); - fn += "/testdata/lefdef/"; - fn += lef_dir; - fn += "/"; - std::string f; + std::string fn = fn_path, f; + ex.read_word_or_quoted (f); + fn += f; + + ld.read_map_file (fn, layout); + + } else if (ex.test ("def:")) { + + std::string fn = fn_path, f; ex.read_word_or_quoted (f); fn += f; @@ -79,17 +86,35 @@ static void run_test (tl::TestBase *_this, const char *lef_dir, const char *file } else if (ex.test ("lef:")) { - std::string fn (priv ? tl::testsrc_private () : tl::testsrc ()); - fn += "/testdata/lefdef/"; - fn += lef_dir; - fn += "/"; - std::string f; + std::string fn = fn_path, f; ex.read_word_or_quoted (f); fn += f; tl::InputStream stream (fn); imp.read_lef (stream, layout, ld); + } else if (ex.test ("gds:")) { + + std::string fn = fn_path, f; + ex.read_word_or_quoted (f); + fn += f; + + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (layout, db::LoadLayoutOptions ()); + + } else if (ex.test("read:")) { + + std::string fn = fn_path, f; + ex.read_word_or_quoted (f); + fn += f; + + tl::InputStream stream (fn); + db::Reader reader (stream); + db::LoadLayoutOptions lo; + lo.set_options (options); + reader.read (layout, lo); + } else { break; @@ -112,6 +137,7 @@ static void run_test (tl::TestBase *_this, const char *lef_dir, const char *file tl::OutputStream stream (tmp_file); db::SaveLayoutOptions options; options.set_format ("OASIS"); + options.set_option_by_name ("oasis_permissive", tl::Variant (true)); db::Writer writer (options); writer.write (layout, stream); } @@ -222,6 +248,7 @@ TEST(15) TEST(16) { run_test (_this, "def7", "lef:cells.lef+lef:tech.lef+def:in.def.gz", "au.oas.gz", default_options ()); + run_test (_this, "def7", "map:in.map+lef:cells.lef+lef:tech.lef+def:in.def.gz", "au_with_map_file.oas.gz", default_options ()); } TEST(17) @@ -231,7 +258,11 @@ TEST(17) TEST(18) { - run_test (_this, "def9", "lef:tech.lef+lef:cells_modified.lef+def:in.def", "au.oas.gz", default_options ()); + db::LEFDEFReaderOptions options = default_options (); + options.set_separate_groups (true); + run_test (_this, "def9", "lef:tech.lef+lef:cells_modified.lef+def:in.def", "au.oas.gz", options); + + run_test (_this, "def9", "lef:tech.lef+lef:cells_modified.lef+def:in.def", "au_nogroups.oas.gz", default_options ()); } TEST(19) @@ -241,10 +272,20 @@ TEST(19) TEST(20) { - run_test (_this, "issue-172", "lef:in.lef+def:in.def", "au.oas.gz", default_options (), false); + run_test (_this, "def11", "lef:test.lef+def:test.def", "au.oas.gz", default_options ()); } TEST(21) +{ + run_test (_this, "def12", "lef:test.lef+def:test.def", "au.oas.gz", default_options ()); +} + +TEST(100) +{ + run_test (_this, "issue-172", "lef:in.lef+def:in.def", "au.oas.gz", default_options (), false); +} + +TEST(101) { db::LEFDEFReaderOptions opt = default_options (); opt.set_produce_pin_names (true); @@ -252,7 +293,7 @@ TEST(21) run_test (_this, "issue-489", "lef:in.lef+def:in.def", "au.oas", opt, false); } -TEST(22) +TEST(102) { db::LEFDEFReaderOptions opt = default_options (); opt.set_produce_pin_names (true); @@ -260,8 +301,83 @@ TEST(22) run_test (_this, "issue-489b", "lef:in_tech.lef+lef:in.lef", "au.oas.gz", opt, false); } -TEST(23) +TEST(103) { run_test (_this, "issue-517", "def:in.def", "au.oas.gz", default_options (), false); } +TEST(104_doxy_vias) +{ + run_test (_this, "doxy_vias", "def:test.def", "au.oas.gz", default_options (), false); +} + +TEST(105_specialnets_geo) +{ + run_test (_this, "specialnets_geo", "lef:test.lef+def:test.def", "au.oas.gz", default_options (), false); + + db::LEFDEFReaderOptions options = default_options (); + options.set_produce_special_routing (false); + run_test (_this, "specialnets_geo", "lef:test.lef+def:test.def", "au_no_spnet.oas.gz", options, false); + + options.set_produce_special_routing (true); + options.set_special_routing_datatype (10); + options.set_special_routing_suffix (".SPNET"); + + options.set_via_geometry_datatype (11); + options.set_via_geometry_suffix (".VIA"); + + run_test (_this, "specialnets_geo", "lef:test.lef+def:test.def", "au_spnet_mapped.oas.gz", options, false); +} + +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); +} + +TEST(109_foreigncell) +{ + run_test (_this, "foreigncell", "gds:foreign.gds+lef:in_tech.lef+lef:in.lef+def:in.def", "au.oas.gz", default_options (), false); + + db::LEFDEFReaderOptions options = default_options (); + + run_test (_this, "foreigncell", "gds:foreign.gds+lef:in_tech.lef+lef:in2.lef+def:in.def", "au_default.oas.gz", options, false); + + options.set_macro_resolution_mode (1); + + run_test (_this, "foreigncell", "gds:foreign.gds+lef:in_tech.lef+lef:in2.lef+def:in.def", "au_ignore_foreign.oas.gz", options, false); + + options.set_macro_resolution_mode (2); + + run_test (_this, "foreigncell", "gds:foreign.gds+lef:in_tech.lef+lef:in.lef+def:in.def", "au_always_foreign.oas.gz", options, false); +} + +TEST(110_lefpins) +{ + db::LEFDEFReaderOptions options = default_options (); + options.set_produce_lef_pins (false); + run_test (_this, "lefpins", "lef:in_tech.lef+lef:in.lef+def:in.def", "au_no_lefpins.oas.gz", options, false); + + options.set_produce_lef_pins (true); + options.set_lef_pins_datatype (10); + options.set_lef_pins_suffix (".LEFPIN"); + + run_test (_this, "lefpins", "lef:in_tech.lef+lef:in.lef+def:in.def", "au_lefpins_mapped.oas.gz", options, false); +} + +TEST(111_mapfile) +{ + db::LEFDEFReaderOptions options = default_options (); + options.set_map_file ("test.map"); + + run_test (_this, "mapfile", "read:in.def", "au.oas.gz", options, false); +} diff --git a/src/plugins/streamers/lefdef/unit_tests/unit_tests.pro b/src/plugins/streamers/lefdef/unit_tests/unit_tests.pro index 93529fc7f..3958da4b2 100644 --- a/src/plugins/streamers/lefdef/unit_tests/unit_tests.pro +++ b/src/plugins/streamers/lefdef/unit_tests/unit_tests.pro @@ -6,7 +6,7 @@ TARGET = lefdef_tests include($$PWD/../../../../lib_ut.pri) SOURCES = \ - dbLEFDEFImport.cc + dbLEFDEFImportTests.cc INCLUDEPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin $$PWD/../../../common DEPENDPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin $$PWD/../../../common diff --git a/src/plugins/streamers/magic/db_plugin/dbMAGReader.cc b/src/plugins/streamers/magic/db_plugin/dbMAGReader.cc index b420321c7..f60be213e 100644 --- a/src/plugins/streamers/magic/db_plugin/dbMAGReader.cc +++ b/src/plugins/streamers/magic/db_plugin/dbMAGReader.cc @@ -111,7 +111,7 @@ MAGReader::read (db::Layout &layout, const db::LoadLayoutOptions &options) m_tech.clear (); { - tl::SelfTimer timer (tl::verbosity () >= 21, "Reading MAGIC file tree"); + tl::SelfTimer timer (tl::verbosity () >= 11, "Reading MAGIC file tree"); // This is the seed do_read (layout, top_cell, m_stream); diff --git a/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc b/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc index 029dc7f5a..6311ff2cf 100644 --- a/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc +++ b/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc @@ -689,8 +689,6 @@ static const char magic_bytes[] = { "%SEMI-OASIS\015\012" }; void OASISReader::do_read (db::Layout &layout) { - tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("File read: ")) + m_stream.source ()); - unsigned char r; char *mb; diff --git a/testdata/lefdef/doxy_vias/au.oas.gz b/testdata/lefdef/doxy_vias/au.oas.gz new file mode 100644 index 000000000..c01179c1f Binary files /dev/null and b/testdata/lefdef/doxy_vias/au.oas.gz differ diff --git a/testdata/lefdef/doxy_vias/test.def b/testdata/lefdef/doxy_vias/test.def new file mode 100644 index 000000000..6381b8523 --- /dev/null +++ b/testdata/lefdef/doxy_vias/test.def @@ -0,0 +1,28 @@ + +VERSION 5.8 ; +DIVIDERCHAR "/" ; +BUSBITCHARS "[]" ; +DESIGN chip_top ; +UNITS DISTANCE MICRONS 1000 ; +DIEAREA ( 30000 3000 ) ( 10000000 4000 ) ; +VIAS 1 ; + - VIA1_dummy + + RECT M1 ( -200 -140 ) ( 200 140 ) + + RECT VIA1 ( -100 -100 ) ( 100 100 ) + + RECT M2 ( -300 -120 ) ( 300 120 ) ; +END VIAS +SPECIALNETS 1 ; +- dummy + + ROUTED M1 150 + SHAPE IOWIRE ( 40000 3600 ) VIA1_dummy DO 16000 BY 1 STEP 700 0 +; +END SPECIALNETS +SCANCHAINS 77 ; +- chain1_clock1 ++ PARTITION clock1 ++ START block1/bsr_reg_0 Q ++ FLOATING +block1/pgm_cgm_en_reg_reg ( IN SD ) ( OUT QZ ) +block1/start_reset_dd_reg ( IN SD ) ( OUT QZ ) ++ STOP block1/start_reset_d_reg SD ; +END SCANCHAINS +END DESIGN diff --git a/testdata/lefdef/foreigncell/au.oas.gz b/testdata/lefdef/foreigncell/au.oas.gz new file mode 100644 index 000000000..4aedac249 Binary files /dev/null and b/testdata/lefdef/foreigncell/au.oas.gz differ diff --git a/testdata/lefdef/foreigncell/au_always_foreign.oas.gz b/testdata/lefdef/foreigncell/au_always_foreign.oas.gz new file mode 100644 index 000000000..4aedac249 Binary files /dev/null and b/testdata/lefdef/foreigncell/au_always_foreign.oas.gz differ diff --git a/testdata/lefdef/foreigncell/au_default.oas.gz b/testdata/lefdef/foreigncell/au_default.oas.gz new file mode 100644 index 000000000..6362bf9f1 Binary files /dev/null and b/testdata/lefdef/foreigncell/au_default.oas.gz differ diff --git a/testdata/lefdef/foreigncell/au_ignore_foreign.oas.gz b/testdata/lefdef/foreigncell/au_ignore_foreign.oas.gz new file mode 100644 index 000000000..c9dd21723 Binary files /dev/null and b/testdata/lefdef/foreigncell/au_ignore_foreign.oas.gz differ diff --git a/testdata/lefdef/foreigncell/foreign.gds b/testdata/lefdef/foreigncell/foreign.gds new file mode 100644 index 000000000..11d3f869e Binary files /dev/null and b/testdata/lefdef/foreigncell/foreign.gds differ diff --git a/testdata/lefdef/foreigncell/in.def b/testdata/lefdef/foreigncell/in.def new file mode 100644 index 000000000..7cf1c70b3 --- /dev/null +++ b/testdata/lefdef/foreigncell/in.def @@ -0,0 +1,17 @@ + +VERSION 5.8 ; +DIVIDERCHAR "/" ; +BUSBITCHARS "[]" ; +DESIGN foreigncells ; +UNITS DISTANCE MICRONS 1000 ; + +DIEAREA ( 0 0 ) ( 1000 2000 ) ; + +COMPONENTS 3 ; + - macro1 macro1 + PLACED ( 0 0 ) N ; + - macro2 macro2 + PLACED ( 0 500 ) E ; + - macro3 macro3 + PLACED ( 0 1000 ) N ; +END COMPONENTS + +END DESIGN + diff --git a/testdata/lefdef/foreigncell/in.lef b/testdata/lefdef/foreigncell/in.lef new file mode 100644 index 000000000..99bd74c57 --- /dev/null +++ b/testdata/lefdef/foreigncell/in.lef @@ -0,0 +1,21 @@ +MACRO macro1 + CLASS CORE ; + FOREIGN foreign1 0.13 0.5 W ; + ORIGIN 0.035 0.235 ; + SIZE 0.07 BY 0.47 ; +END macro1 + +MACRO macro2 + CLASS CORE ; + FOREIGN foreign2 -0.15 0.25 ; + ORIGIN 0.235 0.035 ; + SIZE 0.47 BY 0.07 ; +END macro2 + +MACRO macro3 + CLASS CORE ; + FOREIGN macro3 -1.0 1.0 ; + ORIGIN 0.0 0.0 ; + SIZE 1.0 BY 0.4 ; +END macro3 + diff --git a/testdata/lefdef/foreigncell/in2.lef b/testdata/lefdef/foreigncell/in2.lef new file mode 100644 index 000000000..7c9556cc7 --- /dev/null +++ b/testdata/lefdef/foreigncell/in2.lef @@ -0,0 +1,44 @@ +MACRO macro1 + CLASS CORE ; + ORIGIN 0.035 0.235 ; + SIZE 0.07 BY 0.47 ; + PIN Z + PORT + LAYER M1 ; + RECT -0.02 0 0.02 0.2 ; + RECT -0.03 -0.2 0.01 -0.1 ; + VIA 0.0 0.2 square ; + VIA 0.01 -0.2 square ; + END + END Z +END macro1 + +MACRO macro2 + CLASS CORE ; + FOREIGN foreign2 -0.15 0.25 ; + ORIGIN 0.235 0.035 ; + SIZE 0.47 BY 0.07 ; + PIN Z + PORT + LAYER M1 ; + RECT 0 -0.02 -0.2 0.02 ; + RECT 0.2 -0.03 0.1 0.01 ; + VIA -0.2 0.0 square ; + VIA 0.2 0.01 square ; + END + END Z +END macro2 + +MACRO macro3 + CLASS CORE ; + FOREIGN macro3 -1.0 1.0 ; + ORIGIN 0.0 0.0 ; + SIZE 1.0 BY 1.0 ; + PIN Z + PORT + LAYER M1 ; + RECT 0.2 0.2 0.3 0.5 ; + END + END Z +END macro3 + diff --git a/testdata/lefdef/foreigncell/in_tech.lef b/testdata/lefdef/foreigncell/in_tech.lef new file mode 100644 index 000000000..eb0e75b0b --- /dev/null +++ b/testdata/lefdef/foreigncell/in_tech.lef @@ -0,0 +1,36 @@ +LAYER OD + TYPE IMPLANT ; +END OD +LAYER VTS_N + TYPE IMPLANT ; +END VTS_N +LAYER VTS_P + TYPE IMPLANT ; +END VTS_P +LAYER M0OD + TYPE IMPLANT ; +END M0OD +LAYER M0PO + TYPE MASTERSLICE ; +END M0PO +LAYER VIA0 + TYPE CUT ; +END VIA0 +LAYER M1 + TYPE MASTERSLICE ; +END M1 +LAYER VIA1 + TYPE CUT ; +END VIA1 +LAYER M2 + TYPE MASTERSLICE ; +END M2 + +VIA square + LAYER M0PO ; + RECT -0.006 -0.006 0.006 0.006 ; + LAYER VIA0 ; + RECT -0.006 -0.006 0.006 0.006 ; + LAYER M1 ; + RECT -0.006 -0.006 0.006 0.006 ; +END square diff --git a/testdata/lefdef/issue-489b/in.lef b/testdata/lefdef/issue-489b/in.lef index 857ae0d04..05832b7bd 100644 --- a/testdata/lefdef/issue-489b/in.lef +++ b/testdata/lefdef/issue-489b/in.lef @@ -1,6 +1,5 @@ MACRO dummy CLASS CORE ; - FOREIGN dummy 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 0.384 BY 0.480 ; SYMMETRY X Y ; diff --git a/testdata/lefdef/lefpins/au_lefpins_mapped.oas.gz b/testdata/lefdef/lefpins/au_lefpins_mapped.oas.gz new file mode 100644 index 000000000..80c578b58 Binary files /dev/null and b/testdata/lefdef/lefpins/au_lefpins_mapped.oas.gz differ diff --git a/testdata/lefdef/lefpins/au_no_lefpins.oas.gz b/testdata/lefdef/lefpins/au_no_lefpins.oas.gz new file mode 100644 index 000000000..099aeed88 Binary files /dev/null and b/testdata/lefdef/lefpins/au_no_lefpins.oas.gz differ diff --git a/testdata/lefdef/lefpins/in.def b/testdata/lefdef/lefpins/in.def new file mode 100644 index 000000000..58d6e328b --- /dev/null +++ b/testdata/lefdef/lefpins/in.def @@ -0,0 +1,15 @@ + +VERSION 5.8 ; +DIVIDERCHAR "/" ; +BUSBITCHARS "[]" ; +DESIGN foreigncells ; +UNITS DISTANCE MICRONS 1000 ; + +DIEAREA ( 0 0 ) ( 1000 2000 ) ; + +COMPONENTS 3 ; + - macro1 macro1 + PLACED ( 0 0 ) N ; +END COMPONENTS + +END DESIGN + diff --git a/testdata/lefdef/lefpins/in.lef b/testdata/lefdef/lefpins/in.lef new file mode 100644 index 000000000..e2751e688 --- /dev/null +++ b/testdata/lefdef/lefpins/in.lef @@ -0,0 +1,15 @@ +MACRO macro1 + CLASS CORE ; + ORIGIN 0.000 0.000 ; + SIZE 0.384 BY 0.480 ; + PIN Z + PORT + LAYER M1 ; + RECT 0.306 0.357 0.318 0.403 ; + RECT 0.318 0.115 0.352 0.403 ; + VIA 0.336 0.167 square ; + VIA 0.336 0.351 square ; + END + END Z +END macro1 + diff --git a/testdata/lefdef/lefpins/in_tech.lef b/testdata/lefdef/lefpins/in_tech.lef new file mode 100644 index 000000000..eb0e75b0b --- /dev/null +++ b/testdata/lefdef/lefpins/in_tech.lef @@ -0,0 +1,36 @@ +LAYER OD + TYPE IMPLANT ; +END OD +LAYER VTS_N + TYPE IMPLANT ; +END VTS_N +LAYER VTS_P + TYPE IMPLANT ; +END VTS_P +LAYER M0OD + TYPE IMPLANT ; +END M0OD +LAYER M0PO + TYPE MASTERSLICE ; +END M0PO +LAYER VIA0 + TYPE CUT ; +END VIA0 +LAYER M1 + TYPE MASTERSLICE ; +END M1 +LAYER VIA1 + TYPE CUT ; +END VIA1 +LAYER M2 + TYPE MASTERSLICE ; +END M2 + +VIA square + LAYER M0PO ; + RECT -0.006 -0.006 0.006 0.006 ; + LAYER VIA0 ; + RECT -0.006 -0.006 0.006 0.006 ; + LAYER M1 ; + RECT -0.006 -0.006 0.006 0.006 ; +END square diff --git a/testdata/lefdef/mapfile/au.oas.gz b/testdata/lefdef/mapfile/au.oas.gz new file mode 100644 index 000000000..629c7144b Binary files /dev/null and b/testdata/lefdef/mapfile/au.oas.gz differ diff --git a/testdata/lefdef/mapfile/in.def b/testdata/lefdef/mapfile/in.def new file mode 100644 index 000000000..f24be607b --- /dev/null +++ b/testdata/lefdef/mapfile/in.def @@ -0,0 +1,32 @@ + +VERSION 5.8 ; +DIVIDERCHAR "/" ; +BUSBITCHARS "[]" ; +DESIGN mapfile ; +UNITS DISTANCE MICRONS 1000 ; + +DIEAREA ( 0 0 ) ( 1000 2000 ) ; + +COMPONENTS 3 ; + - macro1 macro1 + PLACED ( 0 0 ) N ; +END COMPONENTS + +SPECIALNETS 1 ; +- VDD ( * VDD ) ++ ROUTED M1 50 + SHAPE STRIPE ( 500 0 ) ( 500 500 25 ) square ( 0 500 ) ++ USE POWER ; +END SPECIALNETS + +PINS 1 ; +- VDD + NET VDD + SPECIAL + DIRECTION INOUT + USE POWER + + LAYER M1 ( 0 0 ) ( 50 70 ) + ; +END PINS + +NETS 1 ; +- TOP ++ ROUTED M1 ( 100 700 ) ( 500 * ) ; +END NETS + +END DESIGN + diff --git a/testdata/lefdef/mapfile/in.lef b/testdata/lefdef/mapfile/in.lef new file mode 100644 index 000000000..38d550efa --- /dev/null +++ b/testdata/lefdef/mapfile/in.lef @@ -0,0 +1,19 @@ +MACRO macro1 + CLASS CORE ; + ORIGIN 0.035 0.235 ; + SIZE 0.07 BY 0.47 ; + PIN Z + PORT + LAYER M1 ; + RECT -0.02 0 0.02 0.2 ; + RECT -0.03 -0.2 0.01 -0.1 ; + VIA 0.0 0.2 square ; + VIA 0.01 -0.2 square ; + END + END Z + OBS + LAYER M1 ; + RECT -0.035 -0.235 0.035 0.235 ; + END +END macro1 + diff --git a/testdata/lefdef/mapfile/in_tech.lef b/testdata/lefdef/mapfile/in_tech.lef new file mode 100644 index 000000000..83f711256 --- /dev/null +++ b/testdata/lefdef/mapfile/in_tech.lef @@ -0,0 +1,27 @@ +LAYER M0PO + TYPE MASTERSLICE ; + WIDTH 0.02 ; +END M0PO +LAYER VIA0 + TYPE CUT ; +END VIA0 +LAYER M1 + TYPE MASTERSLICE ; + WIDTH 0.025 ; +END M1 +LAYER VIA1 + TYPE CUT ; +END VIA1 +LAYER M2 + TYPE MASTERSLICE ; + WIDTH 0.03 ; +END M2 + +VIA square + LAYER M0PO ; + RECT -0.006 -0.006 0.006 0.006 ; + LAYER VIA0 ; + RECT -0.006 -0.006 0.006 0.006 ; + LAYER M1 ; + RECT -0.006 -0.006 0.006 0.006 ; +END square diff --git a/testdata/lefdef/mapfile/test.map b/testdata/lefdef/mapfile/test.map new file mode 100644 index 000000000..7a8609dad --- /dev/null +++ b/testdata/lefdef/mapfile/test.map @@ -0,0 +1,18 @@ +DIEAREA ALL 100 0 +M0PO LEFPIN,LEFOBS,PIN,NET,SPNET,VIA 10 0 +VIA0 LEFPIN,LEFOBS,VIA,PIN,NET,SPNET 11 0 +M1 LEFPIN 12 0 +M1 LEFOBS 12 1 +M1 PIN 12 2 +M1 NET 12 3 +M1 SPNET 12 4 +M1 VIA 12 5 +M1 FILLOPC 12 100 +M1 FILLOPC:MASK:1 12 101 +M1 FILLOPC:MASK:2 12 102 +M1 BLOCKAGEFILL 12 150 +M1 BLOCKAGE 12 151 +M1 FILL 12 152 +NAME M1/PIN 12 10 +VIA1 LEFPIN,LEFOBS,VIA,PIN,NET,SPNET 13 0 +M2 LEFPIN,LEFOBS,PIN,NET,SPNET,VIA 14 0 diff --git a/testdata/lefdef/scanchain/au.oas.gz b/testdata/lefdef/scanchain/au.oas.gz new file mode 100644 index 000000000..62bd98725 Binary files /dev/null and b/testdata/lefdef/scanchain/au.oas.gz differ diff --git a/testdata/lefdef/scanchain/test.def b/testdata/lefdef/scanchain/test.def new file mode 100644 index 000000000..c0fe77f62 --- /dev/null +++ b/testdata/lefdef/scanchain/test.def @@ -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 diff --git a/testdata/lefdef/specialnets_geo/au.oas.gz b/testdata/lefdef/specialnets_geo/au.oas.gz new file mode 100644 index 000000000..cffe30103 Binary files /dev/null and b/testdata/lefdef/specialnets_geo/au.oas.gz differ diff --git a/testdata/lefdef/specialnets_geo/au_no_spnet.oas.gz b/testdata/lefdef/specialnets_geo/au_no_spnet.oas.gz new file mode 100644 index 000000000..4bf45b031 Binary files /dev/null and b/testdata/lefdef/specialnets_geo/au_no_spnet.oas.gz differ diff --git a/testdata/lefdef/specialnets_geo/au_spnet_mapped.oas.gz b/testdata/lefdef/specialnets_geo/au_spnet_mapped.oas.gz new file mode 100644 index 000000000..7decf1260 Binary files /dev/null and b/testdata/lefdef/specialnets_geo/au_spnet_mapped.oas.gz differ diff --git a/testdata/lefdef/specialnets_geo/test.def b/testdata/lefdef/specialnets_geo/test.def new file mode 100644 index 000000000..b9b3e39c8 --- /dev/null +++ b/testdata/lefdef/specialnets_geo/test.def @@ -0,0 +1,27 @@ + +VERSION 5.8 ; +DIVIDERCHAR "/" ; +BUSBITCHARS "[]" ; +DESIGN chip_top ; +UNITS DISTANCE MICRONS 1000 ; +DIEAREA ( 0 0 ) ( 300 300 ) ; +STYLES 2 ; +- STYLE 1 ( 30 10 ) ( 10 30 ) ( -10 30 ) ( -30 10 ) ( -30 -10 ) ( -10 -30 ) ( 10 -30 ) ( 30 -10 ) ; +END STYLES +VIAS 1 ; + - VIA1_dummy + + RECT M1 ( -20 -15 ) ( 20 15 ) + + RECT VIA1 ( -10 -10 ) ( 10 10 ) + + RECT M2 ( -25 -25 ) ( 25 25 ) ; +END VIAS +SPECIALNETS 1 ; +- dummy + + ROUTED + RECT M2 ( 350 0 ) ( 200 100 ) + + POLYGON M1 ( 300 0 ) ( 300 50 ) ( 350 50 ) ( 400 100 ) ( 400 0 ) + + ROUTED + POLYGON M2 ( 300 150 ) ( 300 200 ) ( 350 200 ) ( 400 250 ) ( 400 150 ) + + RECT M1 ( 0 0 ) ( 100 200 ) + + ROUTED M1 30 ( 0 0 15 ) ( 100 0 0 ) VIA1_dummy ( 100 100 10 ) + + ROUTED M2 50 + SHAPE RING + STYLE 1 ( 0 100 ) ( 100 200 ) ( 200 200 ) +; +END SPECIALNETS +END DESIGN diff --git a/testdata/lefdef/specialnets_geo/test.lef b/testdata/lefdef/specialnets_geo/test.lef new file mode 100644 index 000000000..da907c86d --- /dev/null +++ b/testdata/lefdef/specialnets_geo/test.lef @@ -0,0 +1,24 @@ +VERSION 5.8 ; +BUSBITCHARS "[]" ; +DIVIDERCHAR "/" ; + +UNITS + DATABASE MICRONS 1000 ; +END UNITS + +MANUFACTURINGGRID 0.001 ; + +LAYER M1 + TYPE ROUTING ; +END M1 + +LAYER VIA1 + TYPE CUT ; +END VIA1 + +LAYER M2 + TYPE ROUTING ; + WIDTH 0.05 ; +END M2 + +END LIBRARY diff --git a/testdata/lefdef/specialwidths/au.oas.gz b/testdata/lefdef/specialwidths/au.oas.gz new file mode 100644 index 000000000..fee70e139 Binary files /dev/null and b/testdata/lefdef/specialwidths/au.oas.gz differ diff --git a/testdata/lefdef/specialwidths/test.def b/testdata/lefdef/specialwidths/test.def new file mode 100644 index 000000000..9f53fde84 --- /dev/null +++ b/testdata/lefdef/specialwidths/test.def @@ -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 diff --git a/testdata/lefdef/specialwidths/test.lef b/testdata/lefdef/specialwidths/test.lef new file mode 100644 index 000000000..2d0b5edc9 --- /dev/null +++ b/testdata/lefdef/specialwidths/test.lef @@ -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 diff --git a/testdata/lefdef/wrongdirection/au.oas.gz b/testdata/lefdef/wrongdirection/au.oas.gz new file mode 100644 index 000000000..92712cdd3 Binary files /dev/null and b/testdata/lefdef/wrongdirection/au.oas.gz differ diff --git a/testdata/lefdef/wrongdirection/test.def b/testdata/lefdef/wrongdirection/test.def new file mode 100644 index 000000000..e533260cf --- /dev/null +++ b/testdata/lefdef/wrongdirection/test.def @@ -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 diff --git a/testdata/lefdef/wrongdirection/test.lef b/testdata/lefdef/wrongdirection/test.lef new file mode 100644 index 000000000..36b5ae01c --- /dev/null +++ b/testdata/lefdef/wrongdirection/test.lef @@ -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 diff --git a/testdata/ruby/dbReaders.rb b/testdata/ruby/dbReaders.rb index 4c89cc871..eb33d4c61 100644 --- a/testdata/ruby/dbReaders.rb +++ b/testdata/ruby/dbReaders.rb @@ -249,6 +249,10 @@ class DBReaders_TestClass < TestBase conf.via_geometry_suffix = "XVIA" assert_equal(conf.via_geometry_suffix, "XVIA") + assert_equal(conf.via_cellname_prefix, "VIA_") + conf.via_cellname_prefix = "ABC" + assert_equal(conf.via_cellname_prefix, "ABC") + assert_equal(conf.via_geometry_datatype, 0) conf.via_geometry_datatype = 17 assert_equal(conf.via_geometry_datatype, 17) @@ -265,6 +269,18 @@ class DBReaders_TestClass < TestBase conf.pins_datatype = 18 assert_equal(conf.pins_datatype, 18) + assert_equal(conf.produce_lef_pins, true) + conf.produce_lef_pins = false + assert_equal(conf.produce_lef_pins, false) + + assert_equal(conf.lef_pins_suffix, ".PIN") + conf.lef_pins_suffix = "LEFPIN" + assert_equal(conf.lef_pins_suffix, "LEFPIN") + + assert_equal(conf.lef_pins_datatype, 2) + conf.lef_pins_datatype = 181 + assert_equal(conf.lef_pins_datatype, 181) + assert_equal(conf.produce_obstructions, true) conf.produce_obstructions = false assert_equal(conf.produce_obstructions, false) @@ -313,6 +329,26 @@ class DBReaders_TestClass < TestBase conf.routing_datatype = 22 assert_equal(conf.routing_datatype, 22) + assert_equal(conf.produce_special_routing, true) + conf.produce_special_routing = false + assert_equal(conf.produce_special_routing, false) + + assert_equal(conf.special_routing_suffix, "") + conf.special_routing_suffix = "SPROUT" + assert_equal(conf.special_routing_suffix, "SPROUT") + + assert_equal(conf.special_routing_datatype, 0) + conf.special_routing_datatype = 23 + assert_equal(conf.special_routing_datatype, 23) + + assert_equal(conf.separate_groups, false) + conf.separate_groups = true + assert_equal(conf.separate_groups, true) + + assert_equal(conf.map_file, "") + conf.map_file = "xyz.map" + assert_equal(conf.map_file, "xyz.map") + assert_equal(conf.lef_files.join(","), "") conf.lef_files = [ "u.lef", "v.lef" ] assert_equal(conf.lef_files.join(","), "u.lef,v.lef")