/* KLayout Layout Viewer Copyright (C) 2006-2024 Matthias Koefferlein This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "dbLEFDEFImporter.h" #include "dbLayoutUtils.h" #include "dbTechnology.h" #include "dbShapeProcessor.h" #include "tlStream.h" #include "tlProgress.h" #include "tlFileUtils.h" #include namespace db { // ----------------------------------------------------------------------------------- // Path resolution utility std::string correct_path (const std::string &fn_in, const db::Layout &layout, const std::string &base_path) { const db::Technology *tech = layout.technology (); // Allow LEF reference through expressions, i.e. // $(base_path) - path of the main file // $(tech_dir) - the location of the .lyt file if a technology is specified // $(tech_name) - the name of the technology if one is specified // In addition expressions are interpolated, e.g. "$(env('HOME'))". tl::Eval expr; expr.set_var ("base_path", base_path); if (tech) { expr.set_var ("tech_dir", tech->base_path ()); expr.set_var ("tech_name", tech->name ()); } std::string fn = expr.interpolate (fn_in); if (! tl::is_absolute (fn)) { // if a technology is given and the file can be found in the technology's base path, take it // from there. 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; } } if (! base_path.empty ()) { return tl::combine_path (base_path, fn); } else { return fn; } } else { return fn; } } // ----------------------------------------------------------------------------------- // Utilities static bool is_hex_digit (char c) { char cup = toupper (c); return (cup >= 'A' && cup <= 'F') || (c >= '0' && c <= '9'); } static unsigned int hex_value (char c) { char cup = toupper (c); if (cup >= 'A' && cup <= 'F') { return (cup - 'A') + 10; } else if (c >= '0' && c <= '9') { return c - '0'; } else { return 0; } } std::vector string2masks (const std::string &s) { std::vector res; res.reserve (s.size ()); for (const char *cp = s.c_str (); *cp; ++cp) { if (! is_hex_digit (*cp)) { throw tl::Exception ("Not a hex string: " + s); } res.push_back (hex_value (*cp)); } std::reverse (res.begin (), res.end ()); return res; } static unsigned int mask (const std::vector &masks, unsigned int index) { if (index < (unsigned int) masks.size ()) { return masks [index]; } else { return 0; } } static std::string purpose_to_name (LayerPurpose purpose) { switch (purpose) { case Outline: return "OUTLINE"; case Regions: return "REGION"; case RegionsGuide: return "REGIONGUIDE"; case RegionsFence: return "REGIONFENCE"; case RegionsNone: return "REGIONNONE"; case PlacementBlockage: return "BLOCKAGE"; case Routing: return "NET"; case SpecialRouting: return "SPNET"; case ViaGeometry: return "VIA"; case Label: return "LABEL"; case LEFLabel: return "LEFLABEL"; case Pins: return "PIN"; case Fills: return "FILL"; case FillsOPC: return "FILLOPC"; case LEFPins: return "LEFPIN"; case Obstructions: return "LEFOBS"; case Blockage: return "BLK"; case All: return "ALL"; default: return std::string (); } } static std::string layer_spec_to_name (const std::string &layer_name, LayerPurpose purpose, unsigned int mask, const db::DVector &via_size) { std::string ps = purpose_to_name (purpose); std::string n = layer_name; if (! n.empty ()) { n += "."; } n += ps; if (mask > 0) { n += ":"; n += tl::to_string (mask); } if (via_size != db::DVector ()) { n += ":SIZE"; n += tl::sprintf ("%.12gX%.12g", via_size.x (), via_size.y ()); } return n; } // ----------------------------------------------------------------------------------- // RuleBasedViaGenerator implementation RuleBasedViaGenerator::RuleBasedViaGenerator () : LEFDEFLayoutGenerator (), m_bottom_mask (0), m_cut_mask (0), m_top_mask (0), m_rows (1), m_columns (1) { } void RuleBasedViaGenerator::create_cell (LEFDEFReaderState &reader, Layout &layout, db::Cell &cell, const std::vector *maskshift_layers, const std::vector &masks, const LEFDEFNumberOfMasks *nm) { // will not be used with an external maskshift layer stack tl_assert (maskshift_layers == 0); unsigned int mask_bottom = mask (masks, 0), mask_cut = mask (masks, 1), mask_top = mask (masks, 2); if (mask_bottom == 0) { mask_bottom = m_bottom_mask; } if (mask_cut == 0) { mask_cut = m_cut_mask; } if (mask_top == 0) { mask_top = m_top_mask; } unsigned int num_cut_masks = nm ? nm->number_of_masks (m_cut_layer) : 1; // NOTE: missing cuts due to pattern holes don't change mask assignment // special rounding to ensure the dimensions are correct for non-even width or height (issue #1877) db::Vector vs ((m_cutsize.x () * m_columns + m_cutspacing.x () * (m_columns - 1)), (m_cutsize.y () * m_rows + m_cutspacing.y () * (m_rows - 1))); if (vs.x () % 2 != 0 || vs.y () % 2 != 0) { reader.warn (tl::sprintf (tl::to_string (tr ("Via has odd width or height (x,y dimension of cut array is %s database units) - this may lead to inaccurate positioning of the via")), vs.to_string ())); } db::Point via_ll = m_offset - db::Vector (vs.x () / 2, vs.y () / 2); db::Box via_box (via_ll, via_ll + vs); std::set dl; dl = reader.open_layer (layout, m_bottom_layer, ViaGeometry, mask_bottom); for (std::set::const_iterator l = dl.begin (); l != dl.end (); ++l) { cell.shapes (*l).insert (db::Polygon (via_box.enlarged (m_be).moved (m_bo))); } dl = reader.open_layer (layout, m_top_layer, ViaGeometry, mask_top); for (std::set::const_iterator l = dl.begin (); l != dl.end (); ++l) { cell.shapes (*l).insert (db::Polygon (via_box.enlarged (m_te).moved (m_to))); } const char *p = m_pattern.c_str (); int rp = m_pattern.empty () ? -1 : 0; const char *p0 = p, *p1 = p; for (int r = 0; r < m_rows; ++r) { if (rp == 0) { if (*p) { // read a new row specification rp = 0; while (*p && is_hex_digit (*p)) { rp = (rp * 16) + hex_value (*p++); } if (*p == '_') { ++p; } p0 = p; if (*p) { while (*p && (is_hex_digit (*p) || toupper (*p) == 'R')) { ++p; } } p1 = p; if (*p == '_') { ++p; } } } if (rp != 0) { if (rp > 0) { --rp; } const char *pp = p0; unsigned int d = 0; int cp = (p == p0 ? -1 : 0); int bit = 0; for (int c = 0; c < m_columns; ++c) { if (cp == 0) { d = 0; cp = 4; bit = 0; if (*pp && pp < p1 && toupper (*pp) == 'R') { ++pp; if (*pp && pp < p1) { cp = 4 * hex_value (*pp++); if (*pp && pp < p1) { d = (unsigned int) hex_value (*pp++); } } } else if (*pp && pp < p1) { d = (unsigned int) hex_value (*pp++); } if (cp > 0) { --cp; } } else if (cp > 0) { --cp; } else { d = 0xf; } if ((d & (0x8 >> (bit++ % 4))) != 0) { db::Vector vbl ((m_cutsize + m_cutspacing).x () * c, (m_cutsize + m_cutspacing).y () * r); db::Box vb (via_box.lower_left () + vbl, via_box.lower_left () + vbl + m_cutsize); unsigned int cm = 0; if (mask_cut > 0) { // This is the core algorithm for mask assignment in patterned vias cm = (mask_cut + r + c - 1) % num_cut_masks + 1; } dl = reader.open_layer (layout, m_cut_layer, ViaGeometry, cm, vb); for (std::set::const_iterator l = dl.begin (); l != dl.end (); ++l) { cell.shapes (*l).insert (db::Polygon (vb)); } } } } } } // ----------------------------------------------------------------------------------- // GeometryBasedViaGenerator implementation GeometryBasedLayoutGenerator::GeometryBasedLayoutGenerator () : LEFDEFLayoutGenerator (), m_fixedmask (false) { // .. nothing yet .. } unsigned int GeometryBasedLayoutGenerator::get_maskshift (const std::string &ln, const std::vector *msl, const std::vector &masks) { if (! msl) { msl = &m_maskshift_layers; } for (std::vector::const_iterator l = msl->begin (); l != msl->end (); ++l) { if (! l->empty () && *l == ln) { return mask (masks, (unsigned int) (l - msl->begin ())); } } return 0; } unsigned int GeometryBasedLayoutGenerator::mask_for (const std::string &ln, unsigned int m, unsigned int mshift, const LEFDEFNumberOfMasks *nm) const { // for FIXEDMASK we don't do any mask shifting if (m_fixedmask || mshift == 0) { return m; } else if (m == 0) { return mshift; } else { return (m + mshift - 2) % nm->number_of_masks (ln) + 1; } } unsigned int GeometryBasedLayoutGenerator::combine_maskshifts (const std::string &ln, unsigned int mshift1, unsigned int mshift2, const LEFDEFNumberOfMasks *nm) const { if (mshift1 == 0 || mshift2 == 0) { return mshift1 + mshift2; } else { return (mshift1 + mshift2 - 2) % nm->number_of_masks (ln) + 1; } } void GeometryBasedLayoutGenerator::create_cell (LEFDEFReaderState &reader, Layout &layout, db::Cell &cell, const std::vector *ext_msl, const std::vector &masks, const LEFDEFNumberOfMasks *nm) { for (std::map , db::Shapes>::const_iterator g = m_shapes.begin (); g != m_shapes.end (); ++g) { unsigned int mshift = get_maskshift (g->first.first, ext_msl, masks); unsigned int mask = mask_for (g->first.first, g->first.second.mask, mshift, nm); std::set dl = reader.open_layer (layout, g->first.first, g->first.second.purpose, mask, g->first.second.via_size); for (std::set::const_iterator l = dl.begin (); l != dl.end (); ++l) { cell.shapes (*l).insert (g->second); } } for (std::list::const_iterator v = m_vias.begin (); v != m_vias.end (); ++v) { LEFDEFLayoutGenerator *g = reader.via_generator (v->name, v->nondefaultrule); if (! g) { continue; } std::vector msl = g->maskshift_layers (); msl.resize (3, std::string ()); unsigned mshift_bottom = get_maskshift (msl [0], ext_msl, masks); unsigned mshift_cut = get_maskshift (msl [1], ext_msl, masks); unsigned mshift_top = get_maskshift (msl [2], ext_msl, masks); db::Cell *vc = reader.via_cell (v->name, v->nondefaultrule, layout, combine_maskshifts (msl [0], v->bottom_mask, mshift_bottom, nm), combine_maskshifts (msl [1], v->cut_mask, mshift_cut, nm), combine_maskshifts (msl [2], v->top_mask, mshift_top, nm), nm); if (vc) { cell.insert (db::CellInstArray (db::CellInst (vc->cell_index ()), v->trans)); } } } template static db::Shape insert_shape (db::Shapes &shapes, const Shape &shape, db::properties_id_type prop_id) { if (prop_id == 0) { return shapes.insert (shape); } else { return shapes.insert (db::object_with_properties (shape, prop_id)); } } void GeometryBasedLayoutGenerator::add_polygon (const std::string &ln, LayerPurpose purpose, const db::Polygon &poly, unsigned int mask, db::properties_id_type prop_id, const db::DVector &via_size) { insert_shape (m_shapes [std::make_pair (ln, LayerDetailsKey (purpose, mask, via_size))], poly, prop_id); } void GeometryBasedLayoutGenerator::add_box (const std::string &ln, LayerPurpose purpose, const db::Box &box, unsigned int mask, db::properties_id_type prop_id, const db::DVector &via_size) { insert_shape (m_shapes [std::make_pair (ln, LayerDetailsKey (purpose, mask, via_size))], box, prop_id); } void GeometryBasedLayoutGenerator::add_path (const std::string &ln, LayerPurpose purpose, const db::Path &path, unsigned int mask, db::properties_id_type prop_id, const db::DVector &via_size) { insert_shape (m_shapes [std::make_pair (ln, LayerDetailsKey (purpose, mask, via_size))], path, prop_id); } void GeometryBasedLayoutGenerator::add_text (const std::string &ln, LayerPurpose purpose, const db::Text &text, unsigned int mask, db::properties_id_type prop_id) { insert_shape (m_shapes [std::make_pair (ln, LayerDetailsKey (purpose, mask))], text, prop_id); } void GeometryBasedLayoutGenerator::add_via (const std::string &vn, const db::Trans &trans, unsigned int bottom_mask, unsigned int cut_mask, unsigned int top_mask) { m_vias.push_back (Via ()); m_vias.back ().name = vn; m_vias.back ().trans = trans; m_vias.back ().bottom_mask = bottom_mask; m_vias.back ().cut_mask = cut_mask; m_vias.back ().top_mask = top_mask; } void GeometryBasedLayoutGenerator::subtract_overlap_from_outline (const std::set &overlap_layers) { db::Shapes all_overlaps; std::vector, db::Shapes>::iterator> to_remove; for (auto s = m_shapes.begin (); s != m_shapes.end (); ++s) { if (overlap_layers.find (s->first.first) != overlap_layers.end ()) { all_overlaps.insert (s->second); to_remove.push_back (s); } } for (auto i = to_remove.begin (); i != to_remove.end (); ++i) { m_shapes.erase (*i); } if (all_overlaps.empty ()) { return; } for (auto s = m_shapes.begin (); s != m_shapes.end (); ++s) { if (s->first.second.purpose != Outline) { continue; } db::ShapeProcessor proc; size_t pn = 0; for (auto sh = s->second.begin (db::ShapeIterator::All); ! sh.at_end (); ++sh) { proc.insert (*sh, pn); pn += 2; } pn = 1; for (auto sh = all_overlaps.begin (db::ShapeIterator::All); ! sh.at_end (); ++sh) { proc.insert (*sh, pn); pn += 2; } db::BooleanOp op (db::BooleanOp::And); db::ShapeGenerator sg (s->second, true /*clear shapes*/); db::PolygonGenerator out (sg, true, true); proc.process (out, op); } } // ----------------------------------------------------------------------------------- // LEFDEFTechnologyComponent implementation LEFDEFReaderOptions::LEFDEFReaderOptions () : m_read_all_layers (true), m_dbu (0.001), m_produce_net_names (true), m_net_property_name (1), m_produce_inst_names (true), m_inst_property_name (1), m_produce_pin_names (false), m_pin_property_name (1), m_produce_cell_outlines (true), m_cell_outline_layer ("OUTLINE"), m_produce_placement_blockages (true), m_placement_blockage_layer ("PLACEMENT_BLK"), m_produce_regions (true), m_region_layer ("REGIONS"), 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_fills (true), m_fills_suffix (".FILL"), m_fills_datatype (5), m_produce_obstructions (true), m_obstructions_suffix (".OBS"), m_obstructions_datatype (3), m_produce_blockages (true), m_blockages_suffix (".BLK"), m_blockages_datatype (4), m_produce_labels (true), m_labels_suffix (".LABEL"), m_labels_datatype (1), m_produce_lef_labels (true), m_lef_labels_suffix (".LABEL"), m_lef_labels_datatype (1), m_produce_routing (true), m_routing_suffix (""), m_routing_datatype (0), m_produce_special_routing (true), m_special_routing_suffix (""), m_special_routing_datatype (0), m_separate_groups (false), m_joined_paths (false), m_map_file (), m_macro_resolution_mode (0), m_read_lef_with_def (true), m_paths_relative_to_cwd (false) { // .. nothing yet .. } LEFDEFReaderOptions::LEFDEFReaderOptions (const LEFDEFReaderOptions &d) : db::FormatSpecificReaderOptions () { operator= (d); } LEFDEFReaderOptions &LEFDEFReaderOptions::operator= (const LEFDEFReaderOptions &d) { if (this != &d) { db::FormatSpecificReaderOptions::operator= (d); m_read_all_layers = d.m_read_all_layers; m_layer_map = d.m_layer_map; m_dbu = d.m_dbu; m_produce_net_names = d.m_produce_net_names; m_net_property_name = d.m_net_property_name; m_produce_inst_names = d.m_produce_inst_names; m_inst_property_name = d.m_inst_property_name; m_produce_pin_names = d.m_produce_pin_names; m_pin_property_name = d.m_pin_property_name; m_produce_cell_outlines = d.m_produce_cell_outlines; m_cell_outline_layer = d.m_cell_outline_layer; m_produce_placement_blockages = d.m_produce_placement_blockages; m_placement_blockage_layer = d.m_placement_blockage_layer; m_produce_regions = d.m_produce_regions; m_region_layer = d.m_region_layer; m_produce_via_geometry = d.m_produce_via_geometry; m_via_geometry_suffix = d.m_via_geometry_suffix; m_via_geometry_suffixes = d.m_via_geometry_suffixes; m_via_geometry_datatype = d.m_via_geometry_datatype; m_via_geometry_datatypes = d.m_via_geometry_datatypes; 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_suffixes = d.m_pins_suffixes; m_pins_datatype = d.m_pins_datatype; m_pins_datatypes = d.m_pins_datatypes; m_produce_lef_pins = d.m_produce_lef_pins; m_lef_pins_suffix = d.m_lef_pins_suffix; m_lef_pins_suffixes = d.m_lef_pins_suffixes; m_lef_pins_datatype = d.m_lef_pins_datatype; m_lef_pins_datatypes = d.m_lef_pins_datatypes; m_produce_fills = d.m_produce_fills; m_fills_suffix = d.m_fills_suffix; m_fills_suffixes = d.m_fills_suffixes; m_fills_datatype = d.m_fills_datatype; m_fills_datatypes = d.m_fills_datatypes; m_produce_obstructions = d.m_produce_obstructions; m_obstructions_suffix = d.m_obstructions_suffix; m_obstructions_datatype = d.m_obstructions_datatype; m_produce_blockages = d.m_produce_blockages; m_blockages_suffix = d.m_blockages_suffix; m_blockages_datatype = d.m_blockages_datatype; m_produce_labels = d.m_produce_labels; m_labels_suffix = d.m_labels_suffix; m_labels_datatype = d.m_labels_datatype; m_produce_lef_labels = d.m_produce_lef_labels; m_lef_labels_suffix = d.m_lef_labels_suffix; m_lef_labels_datatype = d.m_lef_labels_datatype; m_produce_routing = d.m_produce_routing; m_routing_suffix = d.m_routing_suffix; m_routing_suffixes = d.m_routing_suffixes; m_routing_datatype = d.m_routing_datatype; m_routing_datatypes = d.m_routing_datatypes; m_produce_special_routing = d.m_produce_special_routing; m_special_routing_suffix = d.m_special_routing_suffix; m_special_routing_suffixes = d.m_special_routing_suffixes; m_special_routing_datatype = d.m_special_routing_datatype; m_special_routing_datatypes = d.m_special_routing_datatypes; m_separate_groups = d.m_separate_groups; m_joined_paths = d.m_joined_paths; m_map_file = d.m_map_file; m_macro_resolution_mode = d.m_macro_resolution_mode; m_lef_files = d.m_lef_files; m_macro_layout_files = d.m_macro_layout_files; m_read_lef_with_def = d.m_read_lef_with_def; m_paths_relative_to_cwd = d.m_paths_relative_to_cwd; set_macro_layouts (d.macro_layouts ()); } return *this; } db::FormatSpecificReaderOptions * LEFDEFReaderOptions::clone () const { return new LEFDEFReaderOptions (*this); } const std::string & LEFDEFReaderOptions::format_name () const { static const std::string n ("LEFDEF"); return n; } static void set_datatypes (db::LEFDEFReaderOptions *data, void (db::LEFDEFReaderOptions::*clear) (), void (db::LEFDEFReaderOptions::*set_datatype) (int datatype), void (db::LEFDEFReaderOptions::*set_datatype_per_mask) (unsigned int mask, int datatype), const std::string &s) { (data->*clear) (); (data->*set_datatype) (-1); tl::Extractor ex (s.c_str ()); while (! ex.at_end ()) { tl::Extractor ex_saved = ex; unsigned int mask = 0; if (ex.try_read (mask) && ex.test (":")) { int dt = 0; ex.read (dt); (data->*set_datatype_per_mask) (std::max ((unsigned int) 1, mask), dt); } else { ex = ex_saved; int dt = 0; ex.read (dt); (data->*set_datatype) (dt); } if (ex.at_end ()) { break; } else { ex.expect (","); } } } static void set_suffixes (db::LEFDEFReaderOptions *data, void (db::LEFDEFReaderOptions::*clear) (), void (db::LEFDEFReaderOptions::*set_suffix) (const std::string &suffix), void (db::LEFDEFReaderOptions::*set_suffix_per_mask) (unsigned int mask, const std::string &suffix), const std::string &s) { (data->*clear) (); (data->*set_suffix) (std::string ()); tl::Extractor ex (s.c_str ()); while (! ex.at_end ()) { tl::Extractor ex_saved = ex; unsigned int mask = 0; if (ex.try_read (mask) && ex.test (":")) { std::string sfx; ex.read_word_or_quoted (sfx); (data->*set_suffix_per_mask) (std::max ((unsigned int) 1, mask), sfx); } else { ex = ex_saved; std::string sfx; ex.read_word_or_quoted (sfx); (data->*set_suffix) (sfx); } if (ex.at_end ()) { break; } else { ex.expect (","); } } } static std::string get_datatypes (const db::LEFDEFReaderOptions *data, int (db::LEFDEFReaderOptions::*get_datatype) () const, int (db::LEFDEFReaderOptions::*get_datatype_per_mask) (unsigned int mask) const, unsigned int max_mask) { std::string res; int dt0 = (data->*get_datatype) (); if (dt0 >= 0) { res += tl::to_string (dt0); } for (unsigned int i = 0; i <= max_mask; ++i) { int dt = (data->*get_datatype_per_mask) (i); if (dt >= 0 && dt != dt0) { if (! res.empty ()) { res += ","; } res += tl::to_string (i); res += ":"; res += tl::to_string (dt); } } return res; } static std::string get_suffixes (const db::LEFDEFReaderOptions *data, const std::string &(db::LEFDEFReaderOptions::*get_suffix) () const, const std::string &(db::LEFDEFReaderOptions::*get_suffix_per_mask) (unsigned int mask) const, unsigned int max_mask) { std::string res; std::string sfx0 = (data->*get_suffix) (); if (! sfx0.empty ()) { res += tl::to_word_or_quoted_string (sfx0); } for (unsigned int i = 0; i <= max_mask; ++i) { std::string sfx = (data->*get_suffix_per_mask) (i); if (! sfx.empty () && sfx != sfx0) { if (! res.empty ()) { res += ","; } res += tl::to_string (i); res += ":"; res += tl::to_word_or_quoted_string (sfx); } } return res; } void LEFDEFReaderOptions::set_via_geometry_suffix_str (const std::string &s) { set_suffixes (this, &LEFDEFReaderOptions::clear_via_geometry_suffixes_per_mask, &LEFDEFReaderOptions::set_via_geometry_suffix, &LEFDEFReaderOptions::set_via_geometry_suffix_per_mask, s); } std::string LEFDEFReaderOptions::via_geometry_suffix_str () const { return get_suffixes (this, &LEFDEFReaderOptions::via_geometry_suffix, &LEFDEFReaderOptions::via_geometry_suffix_per_mask, max_mask_number ()); } void LEFDEFReaderOptions::set_via_geometry_datatype_str (const std::string &s) { set_datatypes (this, &LEFDEFReaderOptions::clear_via_geometry_datatypes_per_mask, &LEFDEFReaderOptions::set_via_geometry_datatype, &LEFDEFReaderOptions::set_via_geometry_datatype_per_mask, s); } std::string LEFDEFReaderOptions::via_geometry_datatype_str () const { return get_datatypes (this, &LEFDEFReaderOptions::via_geometry_datatype, &LEFDEFReaderOptions::via_geometry_datatype_per_mask, max_mask_number ()); } void LEFDEFReaderOptions::set_pins_suffix_str (const std::string &s) { set_suffixes (this, &LEFDEFReaderOptions::clear_pins_suffixes_per_mask, &LEFDEFReaderOptions::set_pins_suffix, &LEFDEFReaderOptions::set_pins_suffix_per_mask, s); } std::string LEFDEFReaderOptions::pins_suffix_str () const { return get_suffixes (this, &LEFDEFReaderOptions::pins_suffix, &LEFDEFReaderOptions::pins_suffix_per_mask, max_mask_number ()); } void LEFDEFReaderOptions::set_pins_datatype_str (const std::string &s) { set_datatypes (this, &LEFDEFReaderOptions::clear_pins_datatypes_per_mask, &LEFDEFReaderOptions::set_pins_datatype, &LEFDEFReaderOptions::set_pins_datatype_per_mask, s); } std::string LEFDEFReaderOptions::pins_datatype_str () const { return get_datatypes (this, &LEFDEFReaderOptions::pins_datatype, &LEFDEFReaderOptions::pins_datatype_per_mask, max_mask_number ()); } void LEFDEFReaderOptions::set_lef_pins_suffix_str (const std::string &s) { set_suffixes (this, &LEFDEFReaderOptions::clear_lef_pins_suffixes_per_mask, &LEFDEFReaderOptions::set_lef_pins_suffix, &LEFDEFReaderOptions::set_lef_pins_suffix_per_mask, s); } std::string LEFDEFReaderOptions::lef_pins_suffix_str () const { return get_suffixes (this, &LEFDEFReaderOptions::lef_pins_suffix, &LEFDEFReaderOptions::lef_pins_suffix_per_mask, max_mask_number ()); } void LEFDEFReaderOptions::set_lef_pins_datatype_str (const std::string &s) { set_datatypes (this, &LEFDEFReaderOptions::clear_lef_pins_datatypes_per_mask, &LEFDEFReaderOptions::set_lef_pins_datatype, &LEFDEFReaderOptions::set_lef_pins_datatype_per_mask, s); } std::string LEFDEFReaderOptions::lef_pins_datatype_str () const { return get_datatypes (this, &LEFDEFReaderOptions::lef_pins_datatype, &LEFDEFReaderOptions::lef_pins_datatype_per_mask, max_mask_number ()); } void LEFDEFReaderOptions::set_fills_suffix_str (const std::string &s) { set_suffixes (this, &LEFDEFReaderOptions::clear_fills_suffixes_per_mask, &LEFDEFReaderOptions::set_fills_suffix, &LEFDEFReaderOptions::set_fills_suffix_per_mask, s); } std::string LEFDEFReaderOptions::fills_suffix_str () const { return get_suffixes (this, &LEFDEFReaderOptions::fills_suffix, &LEFDEFReaderOptions::fills_suffix_per_mask, max_mask_number ()); } void LEFDEFReaderOptions::set_fills_datatype_str (const std::string &s) { set_datatypes (this, &LEFDEFReaderOptions::clear_fills_datatypes_per_mask, &LEFDEFReaderOptions::set_fills_datatype, &LEFDEFReaderOptions::set_fills_datatype_per_mask, s); } std::string LEFDEFReaderOptions::fills_datatype_str () const { return get_datatypes (this, &LEFDEFReaderOptions::fills_datatype, &LEFDEFReaderOptions::fills_datatype_per_mask, max_mask_number ()); } void LEFDEFReaderOptions::set_routing_suffix_str (const std::string &s) { set_suffixes (this, &LEFDEFReaderOptions::clear_routing_suffixes_per_mask, &LEFDEFReaderOptions::set_routing_suffix, &LEFDEFReaderOptions::set_routing_suffix_per_mask, s); } std::string LEFDEFReaderOptions::routing_suffix_str () const { return get_suffixes (this, &LEFDEFReaderOptions::routing_suffix, &LEFDEFReaderOptions::routing_suffix_per_mask, max_mask_number ()); } void LEFDEFReaderOptions::set_routing_datatype_str (const std::string &s) { set_datatypes (this, &LEFDEFReaderOptions::clear_routing_datatypes_per_mask, &LEFDEFReaderOptions::set_routing_datatype, &LEFDEFReaderOptions::set_routing_datatype_per_mask, s); } std::string LEFDEFReaderOptions::routing_datatype_str () const { return get_datatypes (this, &LEFDEFReaderOptions::routing_datatype, &LEFDEFReaderOptions::routing_datatype_per_mask, max_mask_number ()); } void LEFDEFReaderOptions::set_special_routing_suffix_str (const std::string &s) { set_suffixes (this, &LEFDEFReaderOptions::clear_special_routing_suffixes_per_mask, &LEFDEFReaderOptions::set_special_routing_suffix, &LEFDEFReaderOptions::set_special_routing_suffix_per_mask, s); } std::string LEFDEFReaderOptions::special_routing_suffix_str () const { return get_suffixes (this, &LEFDEFReaderOptions::special_routing_suffix, &LEFDEFReaderOptions::special_routing_suffix_per_mask, max_mask_number ()); } void LEFDEFReaderOptions::set_special_routing_datatype_str (const std::string &s) { set_datatypes (this, &LEFDEFReaderOptions::clear_special_routing_datatypes_per_mask, &LEFDEFReaderOptions::set_special_routing_datatype, &LEFDEFReaderOptions::set_special_routing_datatype_per_mask, s); } std::string LEFDEFReaderOptions::special_routing_datatype_str () const { return get_datatypes (this, &LEFDEFReaderOptions::special_routing_datatype, &LEFDEFReaderOptions::special_routing_datatype_per_mask, max_mask_number ()); } // ----------------------------------------------------------------------------------- // LEFDEFLayerDelegate implementation LEFDEFReaderState::LEFDEFReaderState (const LEFDEFReaderOptions *tc, db::Layout &layout, const std::string &base_path) : mp_importer (0), m_create_layers (true), m_has_explicit_layer_mapping (false), m_laynum (1), mp_tech_comp (tc) { if (! tc) { // use default options } else if (! tc->map_file ().empty ()) { read_map_file (tc->map_file (), layout, base_path); } else { m_layer_map = tc->layer_map (); m_create_layers = tc->read_all_layers (); } } LEFDEFReaderState::~LEFDEFReaderState () { for (std::map, LEFDEFLayoutGenerator *>::const_iterator i = m_via_generators.begin (); i != m_via_generators.end (); ++i) { delete i->second; } m_via_generators.clear (); for (std::map::const_iterator i = m_macro_generators.begin (); i != m_macro_generators.end (); ++i) { delete i->second; } m_macro_generators.clear (); } void LEFDEFReaderState::error (const std::string &msg) { if (mp_importer) { mp_importer->error (msg); } } void LEFDEFReaderState::warn (const std::string &msg, int warn_level) { if (mp_importer) { mp_importer->warn (msg, warn_level); } } void LEFDEFReaderState::register_layer (const std::string &ln) { m_default_number.insert (std::make_pair (ln, m_laynum)); ++m_laynum; } static bool try_read_layers (tl::Extractor &ex, std::vector &layers) { int l = 0; if (! ex.try_read (l)) { return false; } layers.push_back (l); if (ex.test (",")) { do { if (! ex.try_read (l)) { return false; } layers.push_back (l); } while (ex.test (",")); } return true; } static std::string::size_type find_file_sep (const std::string &s, std::string::size_type from) { std::string::size_type p1 = s.find ("+", from); std::string::size_type p2 = s.find (",", from); if (p1 == std::string::npos) { return p2; } else if (p2 == std::string::npos) { return p1; } else { return p1 < p2 ? p1 : p2; } } static std::vector split_file_list (const std::string &infile) { std::vector files; size_t p = 0; for (size_t pp = 0; (pp = find_file_sep (infile, p)) != std::string::npos; p = pp + 1) { files.push_back (std::string (infile, p, pp - p)); } files.push_back (std::string (infile, p)); return files; } void LEFDEFReaderState::read_map_file (const std::string &filename, db::Layout &layout, const std::string &base_path) { m_has_explicit_layer_mapping = true; std::vector paths = split_file_list (filename); std::map, std::vector > layer_map; for (std::vector::const_iterator p = paths.begin (); p != paths.end (); ++p) { read_single_map_file (correct_path (*p, layout, base_path), layer_map); } // build an explicit layer mapping now. m_layers.clear (); m_layer_map.clear (); db::DirectLayerMapping lm (&layout); for (std::map, std::vector >::const_iterator i = layer_map.begin (); i != layer_map.end (); ++i) { for (std::vector::const_iterator j = i->second.begin (); j != i->second.end (); ++j) { unsigned int layer = lm.map_layer (*j).second; m_layers [i->first].insert (layer); m_layer_map.mmap (*j, layer); } } } void LEFDEFReaderState::read_single_map_file (const std::string &path, std::map, std::vector > &layer_map) { tl::InputFile file (path); tl::InputStream file_stream (file); tl::TextInputStream ts (file_stream); tl::log << tl::to_string (tr ("Reading LEF/DEF map file")) << " " << file_stream.absolute_file_path (); // Purpose name to purpose code std::map purpose_translation; purpose_translation ["LEFPIN"] = LEFPins; purpose_translation ["PIN"] = Pins; purpose_translation ["LEFPINNAME"] = LEFLabel; purpose_translation ["PINNAME"] = Label; purpose_translation ["FILL"] = Fills; purpose_translation ["FILLOPC"] = FillsOPC; purpose_translation ["LEFOBS"] = Obstructions; purpose_translation ["SPNET"] = SpecialRouting; purpose_translation ["NET"] = Routing; purpose_translation ["VIA"] = ViaGeometry; purpose_translation ["BLOCKAGE"] = Blockage; purpose_translation ["ALL"] = All; // List of purposes corresponding to ALL LayerPurpose all_purposes[] = { LEFPins, Pins, SpecialRouting, Routing, ViaGeometry }; 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; std::vector layers, datatypes; size_t max_purpose_str = 15; if (! ex.try_read_word (w1) || ! ex.try_read_word (w2, "._$,/:") || ! try_read_layers (ex, layers) || ! try_read_layers (ex, datatypes)) { warn (tl::sprintf (tl::to_string (tr ("Reading layer map file %s, line %d not understood - skipped")), path, ts.line_number ())); continue; } if (w1 == "DIEAREA") { for (std::vector::const_iterator l = layers.begin (); l != layers.end (); ++l) { for (std::vector::const_iterator d = datatypes.begin (); d != datatypes.end (); ++d) { layer_map [std::make_pair (std::string (), LayerDetailsKey (Outline))].push_back (db::LayerProperties (*l, *d, "OUTLINE")); } } } else if (w1 == "REGION") { std::string name = "REGIONS"; LayerPurpose lp = Regions; if (w2 == "FENCE") { name = "REGIONS_FENCE"; lp = RegionsFence; } else if (w2 == "GUIDE") { name = "REGIONS_GUIDE"; lp = RegionsGuide; } else if (w2 == "NONE") { name = "REGIONS_NONE"; lp = RegionsNone; } else if (w2 != "ALL") { warn (tl::sprintf (tl::to_string (tr ("Reading layer map file %s, line %d - ignoring unknowns REGION purpose %s (use FENCE, GUIDE or ALL)")), path, ts.line_number (), w2)); } for (std::vector::const_iterator l = layers.begin (); l != layers.end (); ++l) { for (std::vector::const_iterator d = datatypes.begin (); d != datatypes.end (); ++d) { layer_map [std::make_pair (std::string (), LayerDetailsKey (lp))].push_back (db::LayerProperties (*l, *d, name)); } } } else if (w1 == "BLOCKAGE") { for (std::vector::const_iterator l = layers.begin (); l != layers.end (); ++l) { for (std::vector::const_iterator d = datatypes.begin (); d != datatypes.end (); ++d) { layer_map [std::make_pair (std::string (), LayerDetailsKey (PlacementBlockage))].push_back (db::LayerProperties (*l, *d, "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" // supported purposes: PINS(->Label), LEFPINS(->LEFLabels) std::vector< std::pair > layer_defs; std::vector purposes = tl::split (w2, ","); for (std::vector::const_iterator p = purposes.begin (); p != purposes.end (); ++p) { if (*p == "DIEAREA" || *p == "ALL" || *p == "COMP") { warn (tl::sprintf (tl::to_string (tr ("Reading layer map file %s, line %d: NAME record ignored for entity: %s")), path, ts.line_number (), *p)); } else { std::vector lp = tl::split (*p, "/"); if (lp.size () > 1) { LayerPurpose label_purpose = Pins; std::map::const_iterator i = purpose_translation.find (lp[1]); if (i != purpose_translation.end ()) { label_purpose = i->second; } if (label_purpose == Pins || label_purpose == LEFPins) { layer_defs.push_back (std::make_pair (lp.front (), label_purpose == Pins ? Label : LEFLabel)); } else { warn (tl::sprintf (tl::to_string (tr ("Reading layer map file %s, line %d: NAME record ignored for purpose: %s")), path, ts.line_number (), purpose_to_name (label_purpose))); } } else { layer_defs.push_back (std::make_pair (lp.front (), Label)); layer_defs.push_back (std::make_pair (lp.front (), LEFLabel)); } } } std::string final_name; for (std::vector< std::pair >::const_iterator i = layer_defs.begin (); i != layer_defs.end (); ++i) { if (! final_name.empty ()) { final_name += "/"; } final_name += i->first + "." + purpose_to_name (i->second); } for (std::vector< std::pair >::const_iterator i = layer_defs.begin (); i != layer_defs.end (); ++i) { for (std::vector::const_iterator l = layers.begin (); l != layers.end (); ++l) { for (std::vector::const_iterator d = datatypes.begin (); d != datatypes.end (); ++d) { layer_map [std::make_pair (i->first, LayerDetailsKey (i->second))].push_back (db::LayerProperties (*l, *d, final_name)); } } } } else if (w1 == "COMP") { // ignore "COMP (ALL) ..." warn (tl::sprintf (tl::to_string (tr ("Reading layer map file %s, line %d: COMP entry ignored")), path, ts.line_number ())); } 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::vector purposes = tl::split (w2, ","); std::reverse (purposes.begin (), purposes.end ()); unsigned int mask = 0; for (std::vector::const_iterator p = purposes.begin (); p != purposes.end (); ++p) { std::string p_uc = tl::to_upper_case (*p); tl::Extractor ex (p_uc.c_str ()); std::string ps; ex.read_word_or_quoted (ps); db::DVector via_size; std::map::const_iterator i = purpose_translation.find (ps); if (i != purpose_translation.end ()) { if (i->second == Routing) { if (ex.test (":VOLTAGE:")) { double f = 0.0; ex.read (f); warn (tl::sprintf (tl::to_string (tr ("Reading layer map file %s, line %d: NET voltage constraint ignored for layer %s")), path, ts.line_number (), w1)); } } else if (i->second == ViaGeometry) { if (ex.test (":SIZE:")) { double sx = 0.0, sy = 0.0; ex.read (sx); ex.test("X"); ex.read (sy); via_size = db::DVector (sx, sy); } } } if (ex.test (":MASK:")) { ex.read (mask); } if (i == purpose_translation.end ()) { warn (tl::sprintf (tl::to_string (tr ("Reading layer map file %s, line %d: purpose %s ignored for layer %s")), path, ts.line_number (), ps, w1)); } else if (i->second == All) { for (LayerPurpose *p = all_purposes; p != all_purposes + sizeof (all_purposes) / sizeof (all_purposes[0]); ++p) { translated_purposes.insert (LayerDetailsKey (*p, mask, via_size)); } } else { translated_purposes.insert (LayerDetailsKey (i->second, mask, via_size)); } } // create a visual description string for the combined purposes std::string purpose_str; for (std::set::const_iterator p = translated_purposes.begin (); p != translated_purposes.end (); ++p) { if (p != translated_purposes.begin ()) { purpose_str += "/"; } std::string ps = layer_spec_to_name (std::string (), p->purpose, p->mask, p->via_size); if (p != translated_purposes.begin () && (purpose_str + ps).size () > max_purpose_str) { purpose_str += "..."; break; } else { purpose_str += ps; } } std::string final_name = w1 + "." + purpose_str; for (std::set::const_iterator p = translated_purposes.begin (); p != translated_purposes.end (); ++p) { for (std::vector::const_iterator l = layers.begin (); l != layers.end (); ++l) { for (std::vector::const_iterator d = datatypes.begin (); d != datatypes.end (); ++d) { layer_map [std::make_pair (w1, *p)].push_back (db::LayerProperties (*l, *d, final_name)); } } } } } } } /** * @brief Returns true, if the layer purpose has a fallback */ static bool has_fallback (LayerPurpose p) { return p == RegionsFence || p == RegionsGuide || p == RegionsNone; } std::set LEFDEFReaderState::open_layer (db::Layout &layout, const std::string &n, LayerPurpose purpose, unsigned int mask, const db::DVector &via_size) { std::map , std::set >::const_iterator nl; nl = m_layers.find (std::make_pair (n, LayerDetailsKey (purpose, mask, via_size))); if (nl == m_layers.end ()) { nl = m_layers.find (std::make_pair (n, LayerDetailsKey (purpose, mask))); } if (nl == m_layers.end ()) { std::set ll; if (! m_has_explicit_layer_mapping) { ll = open_layer_uncached (layout, n, purpose, mask); } m_layers.insert (std::make_pair (std::make_pair (n, LayerDetailsKey (purpose, mask)), ll)); if (ll.empty () && ! has_fallback (purpose)) { std::string msg; if (n.empty ()) { msg = tl::to_string (tr ("No mapping for purpose")) + " '" + purpose_to_name (purpose) + "'"; } else { msg = tl::to_string (tr ("No mapping for layer")) + " '" + n + "', purpose '" + purpose_to_name (purpose) + "'"; } if (mask > 0) { msg += tl::to_string (tr (" Mask ")) + tl::to_string (mask); } // not printing via size - too confusing? #if 0 if (via_size != db::DVector ()) { msg += tl::to_string (tr (" Via size ")) + via_size.to_string (); } #endif warn (msg + tl::to_string (tr (" - layer is ignored"))); } return ll; } else { return nl->second; } } /** * @brief Implements implicit layer mapping * * This is how Implicit layer mapping works: * * 1. For named layers (e.g. routing, pin, etc. * * A decorated name is formed from the basic name and the purpose string (e.g. "M1" -> "M1.PIN"). * With the example of "M1" and purpose Pin (decorated name "M1.PIN") and with a tech component datatype specification * of "5" for "Pin", the layer map entries have the following effect: * * Layer map Result * * (nothing) M1.PIN (default/5) (only if "create_all_layers" is ON, "default" is a default number assigned by the reader) * M1.PIN : 1/0 M1.PIN (1/0) * M1.PIN : 1/17 M1.PIN (1/17) * M1 : 1/0 M1.PIN (1/5) * M1 : 1/2 M1.PIN (1/7) (datatypes will add) * M1 M1.PIN (default/5) * M1 : METAL1 METAL1.PIN (default/5) (name is taken from layer map and decorated) * M1 : METAL1 (1/2) METAL1.PIN (1/7) * M1.PIN : METAL1_PIN METAL1_PIN (default/5) (specific name is used without decoration) * M1.PIN : METAL1_PIN (1/17) METAL1_PIN (1/17) (full and specific mapping) * * 2. For general layers (e.g. outline) * * By default, the name, layer and datatype are taken from the tech component's specification. The specification may * lack the layer and datatype and even the name. If the name is missing, it is generated from the purpose. * * Here are some examples for the mapping of "OUTLINE": * * Tech component Layer map Result * * (nothing) (nothing) OUTLINE (only if "create_all_layers" is ON) * OUTL (nothing) OUTL (default/0) ("default" is a default number assigned by the reader) * OUTL (4/17) (nothing) OUTL (4/17) * OUTL OUTL : 5/1 OUTL (5/1) * OUTL (4/17) OUTL : 4/11 OUTL 4/11 * OUTL (4/17) 4/17 : 4/11 OUTL 4/11 * 4/17 4/17 : 4/11 OUTLINE 4/11 */ std::set LEFDEFReaderState::open_layer_uncached(db::Layout &layout, const std::string &n, LayerPurpose purpose, unsigned int mask) { if (n.empty ()) { std::string ld; bool produce = false; if (purpose == Outline) { produce = mp_tech_comp->produce_cell_outlines (); ld = mp_tech_comp->cell_outline_layer (); } else if (purpose == Regions) { produce = mp_tech_comp->produce_regions (); ld = mp_tech_comp->region_layer (); } else if (purpose == PlacementBlockage) { produce = mp_tech_comp->produce_placement_blockages (); ld = mp_tech_comp->placement_blockage_layer (); } if (! produce) { return std::set (); } db::LayerProperties lp; tl::Extractor ex (ld.c_str ()); try { ex.read (lp); } catch (...) { lp.layer = 0; lp.datatype = 0; } // if no name is given, derive one from the purpose if (lp.name.empty ()) { lp.name = purpose_to_name (purpose); } if (lp.layer < 0) { std::map::const_iterator ldef = m_default_number.find (lp.name); if (ldef != m_default_number.end ()) { lp.layer = ldef->second; lp.datatype = 0; } } // employ the layer map to find the target layer std::set ll = m_layer_map.logical (lp, layout); if (ll.empty () && ! m_create_layers) { return std::set (); } std::set res; // map the layers to targets from the layout // (NOTE: the other readers will do this in advance, but LEF/DEF is too dynamic) bool at_least_once = true; for (std::set::const_iterator l = ll.begin (); l != ll.end () || at_least_once; ++l) { at_least_once = false; // If the layer map provides a target, use that one for the layer db::LayerProperties lp_new = lp; const db::LayerProperties *lpp = (l == ll.end () ? 0 : m_layer_map.target (*l)); if (lpp) { if (! lpp->name.empty ()) { lp_new.name = lpp->name; } if (lpp->datatype >= 0) { lp_new.datatype = lpp->datatype; } if (lpp->layer >= 0) { lp_new.layer = lpp->layer; } } bool found = false; for (db::Layout::layer_iterator i = layout.begin_layers (); i != layout.end_layers () && ! found; ++i) { // NOTE: if lp_new only has a name, we also check for the name. Since we assign a default layer/datatype, // otherwise, a "reload" in the UI would not recognize the layer as the same. if ((*i).second->log_equal (lp_new) || (lp_new.is_named () && (*i).second->name == lp_new.name)) { found = true; res.insert ((*i).first); } } if (! found) { res.insert (layout.insert_layer (lp_new)); } if (l == ll.end ()) { break; } } return res; } 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 LEFLabel: produce = mp_tech_comp->produce_lef_labels (); break; case Pins: produce = mp_tech_comp->produce_pins (); break; case Fills: case FillsOPC: produce = mp_tech_comp->produce_fills (); 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::set (); } } std::string name_suffix; int dt = 0; if (mp_tech_comp) { switch (purpose) { case Routing: default: name_suffix = mp_tech_comp->routing_suffix_per_mask (mask); dt = mp_tech_comp->routing_datatype_per_mask (mask); break; case SpecialRouting: name_suffix = mp_tech_comp->special_routing_suffix_per_mask (mask); dt = mp_tech_comp->special_routing_datatype_per_mask (mask); break; case ViaGeometry: name_suffix = mp_tech_comp->via_geometry_suffix_per_mask (mask); dt = mp_tech_comp->via_geometry_datatype_per_mask (mask); break; case Label: name_suffix = mp_tech_comp->labels_suffix (); dt = mp_tech_comp->labels_datatype (); break; case LEFLabel: name_suffix = mp_tech_comp->lef_labels_suffix (); dt = mp_tech_comp->lef_labels_datatype (); break; case Pins: name_suffix = mp_tech_comp->pins_suffix_per_mask (mask); dt = mp_tech_comp->pins_datatype_per_mask (mask); break; case Fills: case FillsOPC: name_suffix = mp_tech_comp->fills_suffix_per_mask (mask); dt = mp_tech_comp->fills_datatype_per_mask (mask); break; case LEFPins: name_suffix = mp_tech_comp->lef_pins_suffix_per_mask (mask); dt = mp_tech_comp->lef_pins_datatype_per_mask (mask); break; case Obstructions: name_suffix = mp_tech_comp->obstructions_suffix (); dt = mp_tech_comp->obstructions_datatype (); break; case Blockage: name_suffix = mp_tech_comp->blockages_suffix (); dt = mp_tech_comp->blockages_datatype (); break; } } // "name" is the decorated name as provided by the tech component's x_suffix specifications. std::string name = n + name_suffix; // Assign a layer number (a default one for now) and the datatype from the tech component's x_datatype specification. db::LayerProperties lp (name); lp.datatype = dt; std::map::const_iterator ldef = m_default_number.find (n); if (ldef != m_default_number.end ()) { lp.layer = ldef->second; } // Route the layer through the layer map, first the decorated name and if there is no mapping, the // undecorated one. std::set ll = m_layer_map.logical (name, layout); bool generic_match = false; if (ll.empty ()) { ll = m_layer_map.logical (n, layout); generic_match = true; } else if (n == name) { // no suffix defined in tech component -> treat as generic match and combine datatypes generic_match = true; } if (ll.empty () && ! m_create_layers) { return std::set (); } std::set res; bool at_least_once = true; for (std::set::const_iterator l = ll.begin (); l != ll.end () || at_least_once; ++l) { at_least_once = false; // If the layer map provides a target, use that one for the layer db::LayerProperties lp_new = lp; const db::LayerProperties *lpp = (l == ll.end () ? 0 : m_layer_map.target (*l)); if (lpp) { lp_new = *lpp; if (lp_new.datatype < 0) { lp_new.datatype = dt; } else if (generic_match) { lp_new.datatype += dt; } if (lp_new.name.empty ()) { lp_new.name = name; } else if (generic_match) { lp_new.name += name_suffix; } } int lfound = -1; if (lp_new.layer >= 0 && lp_new.datatype >= 0) { for (db::Layout::layer_iterator i = layout.begin_layers (); i != layout.end_layers () && lfound < 0; ++i) { if ((*i).second->log_equal (lp_new)) { lfound = int ((*i).first); } } } if (lfound < 0) { res.insert (layout.insert_layer (lp_new)); } else { res.insert ((unsigned int) lfound); db::LayerProperties lp_org = layout.get_properties ((unsigned int) lfound); join_layer_names (lp_org.name, name); layout.set_properties ((unsigned int) lfound, lp_org); } if (l == ll.end ()) { break; } } return res; } } void LEFDEFReaderState::finish (db::Layout &layout) { CommonReaderBase::finish (layout); int lnum = 0; std::set used_numbers; for (db::Layout::layer_iterator l = layout.begin_layers (); l != layout.end_layers (); ++l) { if ((*l).second->layer >= 0) { used_numbers.insert ((*l).second->layer); } } std::map number_for_name = m_default_number; for (std::map::const_iterator ln = number_for_name.begin (); ln != number_for_name.end (); ++ln) { used_numbers.insert (ln->second); } // Assign default numbers and generate a canonical mapping db::LayerMap lm; for (std::map , std::set >::const_iterator l = m_layers.begin (); l != m_layers.end (); ++l) { if (l->second.empty ()) { continue; } std::string n = layer_spec_to_name (l->first.first, l->first.second.purpose, l->first.second.mask, l->first.second.via_size); for (std::set::const_iterator li = l->second.begin (); li != l->second.end (); ++li) { unsigned int layer_index = *li; db::LayerProperties lp = layout.get_properties (layer_index); if (lp.layer < 0) { std::map::const_iterator n4n = number_for_name.end (); if (! l->first.first.empty ()) { n4n = number_for_name.find (l->first.first); } if (n4n == number_for_name.end ()) { do { ++lnum; } while (used_numbers.find (lnum) != used_numbers.end ()); number_for_name.insert (std::make_pair (l->first.first, lnum)); lp.layer = lnum; } else { lp.layer = n4n->second; } } if (lp.datatype < 0) { lp.datatype = 0; } layout.set_properties (layer_index, lp); lm.mmap (db::LayerProperties (n), layer_index, lp); } } // On return we deliver the "canonical" map which lists the decorated name vs. the real ones. m_layer_map = lm; } void LEFDEFReaderState::register_via_cell (const std::string &vn, const std::string &nondefaultrule, LEFDEFLayoutGenerator *generator) { if (m_via_generators.find (std::make_pair (vn, nondefaultrule)) != m_via_generators.end ()) { delete m_via_generators [std::make_pair (vn, nondefaultrule)]; } m_via_generators [std::make_pair (vn, nondefaultrule)] = generator; } LEFDEFLayoutGenerator * LEFDEFReaderState::via_generator (const std::string &vn, const std::string &nondefaultrule) { std::map, LEFDEFLayoutGenerator *>::const_iterator g = m_via_generators.find (std::make_pair (vn, nondefaultrule)); if (g == m_via_generators.end () && ! nondefaultrule.empty ()) { // default rule is fallback g = m_via_generators.find (std::make_pair (vn, std::string ())); } if (g != m_via_generators.end ()) { return g->second; } else { return 0; } } db::Cell * LEFDEFReaderState::via_cell (const std::string &vn, const std::string &nondefaultrule, db::Layout &layout, unsigned int mask_bottom, unsigned int mask_cut, unsigned int mask_top, const LEFDEFNumberOfMasks *nm) { ViaKey vk (vn, nondefaultrule, mask_bottom, mask_cut, mask_top); std::map, LEFDEFLayoutGenerator *>::const_iterator g = m_via_generators.find (std::make_pair (vn, nondefaultrule)); if (g == m_via_generators.end () && ! vk.nondefaultrule.empty ()) { // default rule is fallback g = m_via_generators.find (std::make_pair (vn, std::string ())); vk.nondefaultrule.clear (); } std::map::const_iterator i = m_via_cells.find (vk); if (i == m_via_cells.end ()) { db::Cell *cell = 0; if (g != m_via_generators.end ()) { LEFDEFLayoutGenerator *vg = g->second; std::string n = vn; if (! vk.nondefaultrule.empty ()) { n += "_"; n += vk.nondefaultrule; } if (mask_bottom > 0 || mask_cut > 0 || mask_top > 0) { n += "_"; n += tl::to_string (mask_bottom); n += "_"; n += tl::to_string (mask_cut); n += "_"; n += tl::to_string (mask_top); } std::string cn = mp_tech_comp->via_cellname_prefix () + n; cell = &layout.cell (make_cell (layout, cn.c_str ())); std::vector masks; masks.reserve (3); masks.push_back (mask_bottom); masks.push_back (mask_cut); masks.push_back (mask_top); vg->create_cell (*this, layout, *cell, 0, masks, nm); } m_via_cells[vk] = cell; return cell; } else { tl_assert (! i->second || i->second->layout () == &layout); return i->second; } } void LEFDEFReaderState::register_macro_cell (const std::string &mn, LEFDEFLayoutGenerator *generator) { if (m_macro_generators.find (mn) != m_macro_generators.end ()) { delete m_macro_generators [mn]; } m_macro_generators [mn] = generator; } LEFDEFLayoutGenerator * LEFDEFReaderState::macro_generator (const std::string &mn) { std::map::const_iterator g = m_macro_generators.find (mn); if (g != m_macro_generators.end ()) { return g->second; } else { return 0; } } db::cell_index_type LEFDEFReaderState::foreign_cell (Layout &layout, const std::string &name) { std::map::const_iterator c = m_foreign_cells.find (name); if (c != m_foreign_cells.end ()) { return c->second; } std::pair cc = layout.cell_by_name (name.c_str ()); db::cell_index_type ci; if (cc.first) { ci = cc.second; } else { ci = make_cell (layout, name.c_str ()); layout.cell (ci).set_ghost_cell (true); } m_foreign_cells.insert (std::make_pair (name, ci)); return ci; } std::pair LEFDEFReaderState::macro_cell (const std::string &mn, Layout &layout, const std::vector &maskshift_layers, const std::vector &masks, const MacroDesc ¯o_desc, const LEFDEFNumberOfMasks *nm) { std::map::const_iterator g = m_macro_generators.find (mn); if (g == m_macro_generators.end ()) { return std::make_pair ((db::Cell *) 0, db::Trans ()); } LEFDEFLayoutGenerator *mg = g->second; MacroKey mk; if (mg->is_fixedmask ()) { mk = MacroKey (mn, std::vector ()); } else { mk = MacroKey (mn, masks); } std::map >::const_iterator i = m_macro_cells.find (mk); if (i != m_macro_cells.end ()) { tl_assert (! i->second.first || i->second.first->layout () == &layout); return i->second; } db::Cell *cell = 0; db::Trans tr; if (! macro_desc.foreign_name.empty ()) { db::cell_index_type ci = foreign_cell (layout, macro_desc.foreign_name); db::Cell *foreign_cell = &layout.cell (ci); if (macro_desc.foreign_name != mn) { // create an indirection for renaming the cell cell = &layout.cell (make_cell (layout, mn.c_str ())); cell->insert (db::CellInstArray (db::CellInst (foreign_cell->cell_index ()), db::Trans (db::Point () - macro_desc.origin) * macro_desc.foreign_trans)); } else { // use FOREIGN cell instead of new one cell = foreign_cell; tr = db::Trans (db::Point () - macro_desc.origin) * macro_desc.foreign_trans; } } else if (tech_comp ()->macro_resolution_mode () == 2) { // create a ghost cell always db::cell_index_type ci = foreign_cell (layout, mn); cell = &layout.cell (ci); } else { // actually implement the real cell std::string mask_suffix; if (! mg->is_fixedmask ()) { for (std::vector::const_iterator m = masks.begin (); m != masks.end (); ++m) { mask_suffix += "_"; mask_suffix += tl::to_string (*m); } } std::string cn = mn + mask_suffix; cell = &layout.cell (make_cell (layout, cn.c_str ())); if (mg->is_fixedmask ()) { mg->create_cell (*this, layout, *cell, 0, std::vector (), nm); } else { mg->create_cell (*this, layout, *cell, &maskshift_layers, masks, nm); } } m_macro_cells [mk] = std::make_pair (cell, tr); return std::make_pair (cell, tr); } // ----------------------------------------------------------------------------------- // LEFDEFImporter implementation LEFDEFImporter::LEFDEFImporter (int warn_level) : 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), m_warn_level (warn_level) { // .. nothing yet .. } LEFDEFImporter::~LEFDEFImporter () { // .. nothing yet .. } unsigned int LEFDEFImporter::get_mask (long m) { return (unsigned int) m; } void LEFDEFImporter::read (tl::InputStream &stream, db::Layout &layout, LEFDEFReaderState &state) { tl::log << tl::to_string (tr ("Reading LEF/DEF file")) << " " << stream.absolute_file_path (); m_fn = stream.filename (); tl::AbsoluteProgress progress (tl::to_string (tr ("Reading ")) + m_fn, 1000); progress.set_format (tl::to_string (tr ("%.0fk lines"))); progress.set_format_unit (1000.0); progress.set_unit (10000.0); mp_reader_state = &state; mp_reader_state->attach_reader (this); if (state.tech_comp ()) { m_options = *state.tech_comp (); } m_produce_net_props = false; m_net_prop_name_id = 0; if (m_options.produce_net_names ()) { m_produce_net_props = true; 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 (m_options.produce_inst_names ()) { m_produce_inst_props = true; 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 (m_options.produce_pin_names ()) { m_produce_pin_props = true; m_pin_prop_name_id = layout.properties_repository ().prop_name_id (m_options.pin_property_name ()); } try { mp_progress = &progress; mp_stream = new tl::TextInputStream (stream); do_read (layout); mp_reader_state->attach_reader (0); delete mp_stream; mp_stream = 0; mp_progress = 0; } catch (...) { mp_reader_state->attach_reader (0); delete mp_stream; mp_stream = 0; mp_progress = 0; throw; } } void LEFDEFImporter::error (const std::string &msg) { if (! mp_stream) { throw LEFDEFReaderException (msg, -1, std::string (), m_fn); } else if (m_sections.empty ()) { throw LEFDEFReaderException (msg, int (mp_stream->line_number ()), m_cellname, m_fn); } else { throw LEFDEFReaderException (msg + tl::sprintf (tl::to_string (tr (" (inside %s)")), tl::join (m_sections, "/")), int (mp_stream->line_number ()), m_cellname, m_fn); } } void LEFDEFImporter::warn (const std::string &msg, int wl) { if (m_warn_level < wl) { return; } if (! mp_stream) { tl::warn << msg << tl::to_string (tr (" (file=")) << m_fn << ")"; } else { tl::warn << msg << tl::to_string (tr (" (line=")) << mp_stream->line_number () << tl::to_string (tr (", cell=")) << m_cellname << tl::to_string (tr (", file=")) << m_fn << ")"; } } bool LEFDEFImporter::at_end () { if (m_last_token.empty ()) { if (next ().empty ()) { return true; } } return false; } bool LEFDEFImporter::peek (const std::string &token) { if (m_last_token.empty ()) { if (next ().empty ()) { error ("Unexpected end of file"); } } const char *a = m_last_token.c_str (); const char *b = token.c_str (); while (*a && *b) { if (std::toupper (*a) != std::toupper (*b)) { return false; } ++a, ++b; } return *a == *b; } bool LEFDEFImporter::test (const std::string &token) { if (peek (token)) { // consume when successful m_last_token.clear (); return true; } else { return false; } } void LEFDEFImporter::expect (const std::string &token) { if (! test (token)) { error ("Expected token: " + token); } } 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 ()) { if (next ().empty ()) { error ("Unexpected end of file"); } } double d = 0; try { tl::from_string (m_last_token, d); } catch (...) { error ("Not a floating-point value: " + m_last_token); } m_last_token.clear (); return d; } long LEFDEFImporter::get_long () { if (m_last_token.empty ()) { if (next ().empty ()) { error ("Unexpected end of file"); } } long l = 0; try { tl::from_string (m_last_token, l); } catch (...) { error ("Not an integer value: " + m_last_token); } m_last_token.clear (); return l; } void LEFDEFImporter::take () { if (m_last_token.empty ()) { if (next ().empty ()) { error ("Unexpected end of file"); } } m_last_token.clear (); } std::string LEFDEFImporter::get () { if (m_last_token.empty ()) { if (next ().empty ()) { error ("Unexpected end of file"); } } std::string r; r.swap (m_last_token); return r; } void LEFDEFImporter::enter_section (const std::string &name) { m_sections.push_back (name); } void LEFDEFImporter::leave_section () { m_sections.pop_back (); } const std::string & LEFDEFImporter::next () { unsigned int last_line = (unsigned int) mp_stream->line_number (); m_last_token.clear (); char c; do { while ((c = mp_stream->get_char ()) != 0 && isspace (c)) ; if (c == '#') { while ((c = mp_stream->get_char ()) != 0 && (c != '\015' && c != '\012')) ; } else if (c == '\'' || c == '"') { char quot = c; while ((c = mp_stream->get_char ()) != 0 && c != quot) { if (c == '\\') { c = mp_stream->get_char (); } if (c) { m_last_token += c; } } break; } else if (c) { m_last_token += c; while ((c = mp_stream->get_char ()) != 0 && ! isspace (c)) { if (c == '\\') { c = mp_stream->get_char (); } if (c) { m_last_token += c; } } break; } } while (c); if (mp_stream->line_number () != last_line) { ++*mp_progress; } return m_last_token; } 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)); } }